问题:
给定数字n,求将其分解为多个*方数的和,最少用多少个*方数可以得到。
Example 1: Input: n = 12 Output: 3 Explanation: 12 = 4 + 4 + 4. Example 2: Input: n = 13 Output: 2 Explanation: 13 = 4 + 9. Constraints: 1 <= n <= 104
解法:Binary Search(二分查找)BFS(广度优先搜索)
对于一个数n,
首先,需要找到与它最*的*方数,getmaxsq(n, formar_try)
♻️ 优化:减少查找的消耗:若有上次查找的结果formar_try,那么上限为min(formar_try, n)
base状态:由于题目给定的限制,
1 <= n <= 10^4
那么查找上限,不超过100。
那么,BFS中,
- queue里保存:剩下的当前数字cur,上次查找结果formar_try
- 对于当前cur,我们可拆分的选择有:j:
- getmaxsq(n, formar_try)获得的最大*方数->1 的所有选择。
- 每次,做出选择后,cur-j^2 作为剩下的数字存入queue,待下一次继续拆解。
- 对于当前cur,我们可拆分的选择有:j:
- 遍历层数,即为所求最少的拆分次数。
- 若此时cur-j^2==0,则找到完全拆分的一个解。由于res从小到大,那么第一次找到,即为最少。
代码参考:
1 class Solution { 2 public: 3 int getmaxsq(int n, int right) { 4 int l = 1, r = right; 5 if(n<right) r = n; 6 while(l<r) { 7 int m = l+(r-l)/2; 8 if(m*m >= n) { 9 r = m; 10 } else { 11 l = m+1; 12 } 13 } 14 return l; 15 } 16 int numSquares(int n) { 17 int res=0; 18 if(n==1) return 1; 19 queue<pair<int,int>> q;//leftnum,formartry 20 q.push({n,getmaxsq(n,min(100,n))}); 21 int sz = 0; 22 int cur=0, nextcur=0, trysq=100; 23 while(!q.empty()) { 24 sz=q.size(); 25 res++; 26 for(int i=0; i<sz; i++) { 27 cur = q.front().first; 28 trysq = q.front().second; 29 //printf("cur:%d, trysq:%d ", cur, trysq); 30 q.pop(); 31 for(int j=trysq; j>0; j--) { 32 nextcur = cur-j*j; 33 if(nextcur==0) return res; 34 if(nextcur<0) continue; 35 q.push({nextcur, getmaxsq(nextcur, j)}); 36 } 37 } 38 //printf(" "); 39 } 40 return res; 41 } 42 };