【279】完全平方數(shù)

一、題目

1、題目描述

給定正整數(shù) n,找到若干個完全平方數(shù)(比如 1, 4, 9, 16, ...)使得它們的和等于 n。你需要讓組成和的完全平方數(shù)的個數(shù)最少。

2、示例

示例1:

輸入: n = 12
輸出: 3
解釋: 12 = 4 + 4 + 4.

示例2:

輸入: n = 13
輸出: 2
解釋: 13 = 4 + 9.

二、解題思路

1、思路一

動態(tài)規(guī)劃
動態(tài)規(guī)劃算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然后從這些子問題的解得到原問題的解。
而這個題求正整數(shù)n,我們可以運用動態(tài)規(guī)劃的思想,從1開始,求出直到n的個數(shù)最少的完全平方和。
首先聲明一個n+1大小的數(shù)組dp,那么dp[i]就代表數(shù)字i所需的最少完全平方數(shù)個數(shù),dp[i]初值設為i,即最差情況就是i個1相加。
聲明變量j,j * j就代表平方數(shù),如果dp[i-j * j]+1的個數(shù)比dp[i]小,那么dp[i]就設為dp[i-j * j]+1,這里+1的原因是j * j本身也要算一個數(shù)。

執(zhí)行用時 :30 ms, 在所有 java 提交中擊敗了76.91%的用戶
內(nèi)存消耗 :35.3 MB, 在所有 java 提交中擊敗了42.14%的用戶

2、思路二

BFS廣度優(yōu)先搜索
當每一次都可以判斷出多種情況,有多次的時候就適合用BFS-廣度優(yōu)先遍歷
使用BFS應注意:
隊列:用來存儲每一輪遍歷得到的節(jié)點;
標記:對于遍歷過的節(jié)點,應該將它標記,防止重復遍歷。
我們將它第一個平方數(shù)可能出現(xiàn)的情況做分析 只要 i * i < n 就行
再在此基礎上進行二次可能出現(xiàn)的平方數(shù)分析
注意:為了節(jié)省遍歷的時間,曾經(jīng)( n - 以前出現(xiàn)的平方數(shù)) 這個值出現(xiàn)過,則在此出現(xiàn)這樣的數(shù)時直接忽略。

廣度優(yōu)先搜索

執(zhí)行用時 :15 ms, 在所有 java 提交中擊敗了93.46%的用戶
內(nèi)存消耗 :36.3 MB, 在所有 java 提交中擊敗了39.43%的用戶

3、一個有意思的思路

看到評論里這個思路的時候,默默感嘆吃了沒文化的虧,評論里給出了一個數(shù)學定理,沒仔細研究,有興趣可以看看
四平方定理: 任何一個正整數(shù)都可以表示成不超過四個整數(shù)的平方之和。 推論:滿足四數(shù)平方和定理的數(shù)n(四個整數(shù)的情況),必定滿足 n=4^a(8b+7)

執(zhí)行用時 :8 ms, 在所有 python 提交中擊敗了100.00%的用戶
內(nèi)存消耗 :11.7 MB, 在所有 python 提交中擊敗了44.68%的用戶

三、代碼

1、思路一代碼

class Solution {
    public int numSquares(int n) {
        int[] dp=new int[n+1];
        dp[0]=0;
        for(int i=1;i<=n;i++){
            dp[i]=i;
            for(int j=1;j*j<=i;j++){
                if((dp[i-j*j]+1)<dp[i]){
                    dp[i]=dp[i-j*j]+1;
                }
            }
        }
        return dp[n];
    }
}

2、思路二代碼

public class NumSquares {
    private class Node {
        int val;
        int step;

        public Node(int val, int step) {
            this.val = val;
            this.step = step;
        }
    }

    public int numSquares(int n) {
        Queue<Node> queue = new LinkedList<>();
        queue.add(new Node(n, 1));
        boolean record[] = new boolean[n];
        while (!queue.isEmpty()) {
            int val = queue.peek().val;
            int step = queue.peek().step;
            queue.remove();
            // 每一層的廣度遍歷
            for (int i = 1;; i++) {
                int nextVal = val - i * i;
                // 說明已到最大平方數(shù)
                if (nextVal < 0)
                    break;

                // 由于是廣度遍歷,所以當遍歷到0時,肯定是最短路徑
                if(nextVal == 0)
                    return step;
                
                // 當再次出現(xiàn)時沒有必要加入,因為在該節(jié)點的路徑長度肯定不小于第一次出現(xiàn)的路徑長
                if(!record[nextVal]){
                   queue.add(new Node(nextVal,step + 1));
                   record[nextVal] = true;
                }
            }
        }
        return -1;
    }

}

3、思路三代碼

def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        while n % 4 == 0: 
            n /= 4 
        if n % 8 == 7: 
            return 4 
        a = 0 
        while a**2 <= n: 
            b = int((n - a**2)**0.5) 
            if a**2 + b**2 == n: 
                return (not not a) + (not not b) 
            a += 1 
        return 3

本文涉及引用來自于leetcode
作者:EiletXie
鏈接:https://leetcode-cn.com/problems/perfect-squares/solution/yan-du-you-xian-sou-suo-java-by-eiletxie/
來源:力扣(LeetCode)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 給定正整數(shù) n,找到若干個完全平方數(shù)(比如 1, 4, 9, 16, ...)使得它們的和等于 n。你需要讓組成和...
    上行彩虹人閱讀 205評論 0 0
  • 題目描述 給定正整數(shù) n,找到若干個完全平方數(shù)(比如 1, 4, 9, 16, ...)使得它們的和等于 n。你需...
    莫小鵬閱讀 1,171評論 0 0
  • 給定正整數(shù) n,找到若干個完全平方數(shù)(比如 1, 4, 9, 16, ...)使得它們的和等于 n。你需要讓組成和...
    xgz_pmx閱讀 683評論 0 0
  • https://leetcode-cn.com/problems/perfect-squares/給定正整數(shù) n,...
    青洺想吃棒棒糖閱讀 539評論 0 0
  • 他輕輕一笑于是夜風忽揚吹我發(fā)梢入我心房他輕輕一笑于是晚櫻突放落我肩上入此天堂他輕輕一笑于是百鳥振翅蝴蝶落海楚辭蒼茫。
    七百的路閱讀 280評論 0 3

友情鏈接更多精彩內(nèi)容