這道題跟以前的動態規劃有些區別。刷了很多動態規劃的題目。大部分的結構,都是相似於這種形式java
dp[i] = Math.max(min)(dp[i-n]+k, dp[i-m]+k1) + M
這種形式,涉及到最大小值,確定涉及到題目求解的最值問題code
並且通常絕大多數狀況下是,時間複雜度都是O(n)。leetcode
此次的題目,主要涉及到一些關鍵點的處理。get
若是不考慮這些關鍵點,無非就是io
dp[i] 表示數字爲i的時候,最少的平方數字組成,也就問題所要的答案 dp[i] = dp[i-1] + 1(數字i-1加上1,就能夠獲得i)
不考慮平方數的時候,好比當 n = 4 的時候,dp[4] = dp[3]+1class
可是若是考慮平方數的話,dp[4] = 2^2遍歷
而後就一直糾結關鍵點怎麼處理。看了題解,用了遍歷。動態規劃
for(int i = 1; i <= n; i++){ dp[i] = n; // 等價 dp[i] = dp[i-1]+1; for(int j = 1; i-j*j>=0; j++){ dp[i] = Math.min(dp[i], dp[i-j*j]+1); } }
由於沒法判斷哪一個數的平方能夠知足條件。因此須要去遍歷。好比對於 n = 4,須要去遍歷,4 - 1, 4 - 2^2。須要去取這些遍歷的最小值。時間
注意:由於須要去取這些狀況的最值,因此 min 必須含有其自己,因此這種結構,須要一開始去給dp[i]設置一個大的值,dp[i] = n只是這裏的特殊狀況,其實 dp[i] = dp[i-1]+1 。是不考慮平方數所需最少的數,也就是dp[i]的上界。co
若是還不是很清楚,舉個例子
dp[4] = min(dp[3]+1, dp[4-1]+1, dp[4-2^2]+1) dp[10] = min(dp[9]+1, dp[10-1]+1, dp[10-2^2]+1, dp[10-3^3]+1) 拆解爲——————> dp[4] = min(dp[3]+1, dp[4-1]+1) dp[4] = min(dp[4], dp[4-2^2]+1) ----------->
只不過這個min中所含的參數個數是一直變化的,因此須要遍歷。
其次,由於遍歷,因此必定要與以前求的值進行比較。因此須要在遍歷前進行初始化。
class Solution { public int numSquares(int n) { int[] dp = new int[n+1]; for(int i = 1; i <= n; i++){ dp[i] = dp[i-1]+1; for(int j = 1; i-j*j>=0; j++){ dp[i] = Math.min(dp[i], dp[i-j*j]+1); } } return dp[n]; } }