Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...
) which sum to n.
Example 1:
Input: n =12
Output: 3 Explanation:12 = 4 + 4 + 4.
Example 2:
Input: n =13
Output: 2 Explanation:13 = 4 + 9.
最近复习考试,好几天没刷题了。
这道题从LeetCode讨论区学到了不少,明白了回溯法和动态规划的关系,也复习了一下bfs
首先,解法一(bfs 广度优先搜索):
每次处理递归树的一层,代码如下:
public int numSquares(int n) {
List<Integer> squares = getSquares(n);
Queue<Integer> queue = new LinkedList<>();
queue.offer(n);
boolean[] marked = new boolean[n+1];
//marked[n] = true;
int depth = 0;
while(!queue.isEmpty()){
depth++;
int size = queue.size();
for(int i = 0;i<size;i++){
int prev = queue.poll();
for(int square:squares){
if(prev-square==0) return depth;
else if(prev-square>0 && !marked[prev-square]){
queue.add(prev-square);
marked[prev-square] = true;
}
}
}
}
return -1;
}
private List<Integer> getSquares(int n){
List<Integer> res = new ArrayList<>();
int start = 1;
int add = 3;
while(start<=n){
res.add(start);
start += add;
add += 2;
}
return res;
}
上面这种解法的时间复杂度为O(n*n) 至于怎么证明我也不会
解法二:
动态规划。这里重点是递归关系式 dp[n] = Min{ dp[n - j*j] + 1 }
那么这个关系式是怎么来的呢?其实很简单,看看上面的bfs解法中的图。
只需要用15和16两个例子,自然就会明白了。
//dp O(n*sqrt(n)~O(n*logn)
//递推关系式 dp[n] = Min{ dp[n - j*j] + 1 } 其中 n - j*j >=0 且 j >= 1
public int numSquares(int n) {
int[] dp = new int[n+1];
//dp[0] = 0;
for(int i = 1;i<n+1;i++){
int imin = Integer.MAX_VALUE;
int j = 1;
while(i-j*j>=0){
if(dp[i-j*j]+1<imin){
imin = dp[i-j*j]+1;
}
j++;
}
dp[i] = imin;
}
return dp[n];
}