1. 程式人生 > >[LeetCode]problem 279. Perfect Squares

[LeetCode]problem 279. Perfect Squares

TAG

動態規劃廣度優先搜尋深度優先搜尋

數論四平方和定理三平方和定理

題目連結

方法

不會。不過是一道太有意思的題目了…

首先是DP方法,設R[i]表示數i最少可由R[i]個數的完全平方和構成。那麼遞推關係可以寫作:

R[i] = min( R[i-j*j] + 1 ), 0 < j*j <= i
R[0] = 0   

對我而言,是在是太巧妙了。R[i]的前一個狀態,就是減掉一個數的平方和,結果值對應的那個狀態。真是厲害啊。

接著是BFS。BFS首先把小於N的完全平方和作為圖上的節點。每一步,對當前圖的每一個節點向外擴充套件一步,就是將該節點與小於N的平方和挨個做加,如果等,則路徑長度就是平方和的個數,如果小於,則產生一個新的節點;如果大於,則丟棄。迭代遍歷,直到相等。

DFS,我自己想的… 沒有寫程式碼,不過應該可行。就是和之前的回溯一樣的思想。同樣產生小於N的所有平方和,然後把問題轉化為找K個數,使得k個數的和為目標值。只不過為了保證是最少,需要從大往小遍歷,且數可重複。遍歷過程可剪枝。這麼應該還是可行的。

最後,就是神奇的數學方法了。

  1. 四平方和定理:任意一個正整數都可以表示為4個數的平方和;

  2. 三平方和定理: 如果一個正整數可以表示為4^{a} * (8*b + 7),那麼這個數一定不能表示為3個數的平方和。此時一定需要4個數的平方和相加才能表示(在維基百科上沒有看到)。

  3. 處理2數的平方和,只需i1sqrt(n) , 看 n - i^2是否是完全平方即可。

程式碼

只寫了DP方法。

class Solution {
public:
    int numSquares(int n) {
        if(n <= 0){ return 0 ;}
        vector<int> leastNum(n+1, numeric_limits<int>::max());
        leastNum[0] = 0;
        for(int i = 1; i < n + 1; ++i)
        {
            for(int testNum = 1; testNum * testNum <= i; ++testNum)
            {
                int
preStateIdx = i - testNum * testNum; leastNum[i] = min( leastNum[preStateIdx] + 1, leastNum[i]); } } return leastNum.back(); } };