[LeetCode]problem 279. Perfect Squares
阿新 • • 發佈:2019-02-19
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個數的和為目標值。只不過為了保證是最少,需要從大往小遍歷,且數可重複。遍歷過程可剪枝。這麼應該還是可行的。
最後,就是神奇的數學方法了。
四平方和定理:任意一個正整數都可以表示為4個數的平方和;
三平方和定理: 如果一個正整數可以表示為
4^{a} * (8*b + 7)
,那麼這個數一定不能表示為3個數的平方和。此時一定需要4個數的平方和相加才能表示(在維基百科上沒有看到)。處理2數的平方和,只需
i
從1
到sqrt(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();
}
};