一、题目描述
简单的DP,转化问题为BFS问题
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
二,算法与代码
DP解法:只要发现对于非平方数(例如:2,3,5,6),它们的最小组成一定是由n个平方数和m个非平方数组成,而非平方数其实都只能由N个1组成,如2 = 1+ 1, 3 = 1 + 1 + 1。所以得到转移方程
dp[i]=min(dp[i],1+dp[i−j∗j])
class Solution {
public:
int numSquares(int n) {
int res;
vector<int> dp(n+1, 0);
for(int i = 1; i <= n; i++) {
dp[i] = i+1;
for(int j = 1; j <= sqrt(i); j++) {
dp[i] = min(dp[i], 1+dp[i - j*j]);
}
}
return dp[n];
}
};
BFS解法:如图所示,BFS的解法是先找出原始的小于n的所有平方数(allNs),以此作为第二层结点,通过与allNs中的平方数进行组合,找出可能的其他所有的小于n的结点,不断向外辐射这棵树,直到找到一条路径上的结点的数的和等于n,此时该路径上的数即为n的最小的平方数的组成,数的层数即为所求的最小数。
class Solution {
public:
int numSquares(int n) {
if(n <= 0) return 0;
vector<int> squareNumber, countsOfnumSquares(n+1,0);
for(int i = 0; i*i <= n; i++) {
squareNumber.push_back(i*i); //平方数
countsOfnumSquares[i*i] = 1;//n平方数的 numSquares 为1
if(i*i == n) return 1;
}
queue<int> tmp;
for(int i = 0; i < squareNumber.size(); i++)
tmp.push(squareNumber[i]);
int count = 1;
while(!tmp.empty()) {
count++;
for(int k = 0, size = tmp.size(); k < size; k++) {
int cur = tmp.front();
for(int i = 0; i < squareNumber.size(); i++) {
if(cur + squareNumber[i] == n) {
return count;
} else if(cur + squareNumber[i] < n && countsOfnumSquares[cur+squareNumber[i]] == 0) {
countsOfnumSquares[cur+squareNumber[i]] = count;
tmp.push(cur + squareNumber[i]);
} else if(cur + squareNumber[i] > n) {
break;
}
}
tmp.pop();
}
}
}
};