原题链接:https://leetcode-cn.com/problems/perfect-squares/
相关题目:leetcode算法题–零钱兑换
1、回溯法
就是暴力法,套路就是递归,但是有很多重复计算。
int numSquares(int n) {
return func(n);
}
int func(int n){
int count=INT_MAX;
if(n==0) return 0;
for(int i=1;i*i<=n;i++)
count=min(count,func(n-i*i)+1);
return count;
}
2、回溯法+记忆化
就是在回溯法的基础上,用map存储,减少重复的计算。
int numSquares(int n) {
map<int,int>m;
func(n,m);
return m[n];
}
int func(int n,map<int,int> &m){
int count=INT_MAX;
if(n==0) return 0;
if(m.find(n)!=m.end()) return m[n];
for(int i=1;i*i<=n;i++)
count=min(count,func(n-i*i,m)+1);
m[n]=count;
return count;
}
3、动态规划
相比于回溯法省去了压栈出栈的过程,不过不是很容易想到。
dp[i] i代表数为i,dp[i]代表数为i时最小组合数
转移方程
dp[i]=min(dp[i],dp[i-j*j])+1
代码:
int numSquares(int n){
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=1;j*j<=i;j++){
dp[i]=min(dp[i],dp[i-j*j]+1);
}
}
return dp[n];
}
其实就拿n=12来举例:
dp[0]=0
dp[1]=1
dp[2]=2
dp[3]=3
dp[4]=1
dp[5]=2
dp[6]=3
dp[7]=4
dp[8]=2
dp[9]=1
dp[10]=2
dp[11]=3
dp[12]=3
细细品,j*j起了很大的限制作用