这道题跟以前的动态规划有些区别。刷了很多动态规划的题目。大部分的结构,都是相似于这种形式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]; } }