279. 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
动态规划
设置dp数组,对小于n的每个平方数设置dp=1;
从2开始遍历每个数,对每个数再枚举每种平方数的凑法;
最后返回dp[n]即为答案;
class Solution {
public:
int numSquares(int n) {
//用1,4,9,16……凑n
dp.resize(n+1,INT_MAX);
for(int i=1;i*i<=n;i++){
dp[i*i]=1;
//if(i*i==n) return 1;
}
for(int i=2;i<=n;i++){ //从1~i用数最少的那个+剩余的数
for(int j=1;j*j<i;j++)
dp[i]=min(dp[i],dp[j*j]+dp[i-j*j]);
}
return dp[n];
}
private:
vector<int> dp;
};
贪心算法
递归实现对最少次数的枚举;
(1)将小于等于n的平方数全部保存在map中;
(2)最少数从1开始,递归得到最少树——每次递归遍历map;
(3)递归终止条件——cnt==1时;
class Solution {
public:
int numSquares(int n) {
for(int i=1;i*i<=n;i++)
map[i*i]=1;
//保存所有小于n的平方
int cnt=1;
while(!istrue(n,cnt)) cnt++;
return cnt;
}
private:
unordered_map<int,bool> map;
bool istrue(int n,int cnt){
if(cnt==1) return map.count(n);
for(auto t:map)
if(istrue(n-t.first,cnt-1)) return true;
return false;
}
};
BFS+贪心
从第一层开始找;
每次看前一层的数是否有与平方数相等的数,有则返回当前层数;
无则将上一层的数减去每一个比自己小的平方数,前往下一层;
class Solution {
public:
int numSquares(int n) {
int cnt=0;
for(int i=1;i*i<=n;i++)
cut.push_back(i*i);
queue.insert(n);
while(1){
++cnt;
set<int> next_queue;
for(int tmp:queue){
for(auto c:cut)
{
if(c==tmp) return cnt;
else if(tmp<c) break;
else next_queue.insert(tmp-c);
}
}
queue=next_queue;
}
}
private:
set<int> queue;
vector<int> cut;
};
注意点:使用两个set,代替queue,可有效去重,加快速度;