思路:
方法一:使用广度优先,设置一个队列、一个记录表
方法二:动态规划dp
代码:
方法一:
class Solution {
public int numSquares(int n) {
if(n==0||n==1) return n;
//创建队列
Queue<Integer> queue=new LinkedList<>();
queue.offer(n);
//visited
boolean[] visited=new boolean[n];
int step=1;
while(!queue.isEmpty()){
int size=queue.size();
for(int i=0;i<size;i++){
int cur=queue.poll();
for(int k=1;k*k<=cur;k++){
if(k*k==cur){
//只有相等时才返回
return step;
}
int next=cur-k*k;
if(!visited[next]){
queue.offer(next);
visited[next]=true;
}
}
}
step++;
}
//return step;
throw new IllegalArgumentException("参数错误");
}
}
方法二:
class Solution {
public int numSquares(int n) {
if(n==0||n==1){
return 1;
}
int[] dp=new int[n+1];
//从1开始,下标代表数值
for(int i=1;i<=n;i++){
//初始化
dp[i]=i;
for(int k=1;i-k*k>=0;k++){
//每次都是i-k*k,如果<=0,则表示该平方数符合
//因为该数比前一个数大,所以肯定是在前一个数的基础上要+1
dp[i]=Math.min(dp[i],dp[i-k*k]+1);
}
}
return dp[n];
}
}
分解:
1)广度优先的固定模式:
Queue<Integer> queue=new LinkedList<>();
queue.offer(n);
boolean[] visited=new boolean[n];
int step=1;
while(!queue.isEmpty()){
int size=queue.size();
for(int i=0;i<size;i++){
int cur=queue.poll();
...
int next=xxx;
if(!visited[next]){
queue.offer(next);
visited[next]=true;
}
}
}
2)注意:
i)每次出队列之前,都记录一下这次队列中有多少个元素
ii)改变了当前元素后,判断是否访问过,若无,则1)加入队列 2)设置为访问
3)方法二:
i)初始化:从1开始,下标代表数值
ii)每次都是i-k*k,如果<=0,则表示该平方数符合
因为该数比前一个数大,所以肯定是在前一个数的基础上dp+1