Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

Example 1:

Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
Example 2: Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

解题思路:

第一种方案: 二维dp

和为n的数,要么以1开头,要么以4开头,要么以9开头,依次类推,本题就是求这些可能方案中,需要平方数个数最少的那组解

dp[k][n] - 表示以k开头的平方数序列,和为n时,最少需要的平方数个数

进一步递推可得

dp[k][n] = 1 + min{dp[k][n - k], dp[nextK][n - k], ...}

因为,取k是一步,取完k之后,问题变为求解和为n - k的最优解, 我们可以继续取k, 即dp[k][n - k], 或者我们直接取下一个k, dp[nextK][n - k], ....,

最终找到和为n - k时的最优解, 对解加1,即为和为n时,以k开头的最优解.

最终,我们遍历dp[i][n] i = 1, 4, 9, ..., n ,即可以得到和为n的解.

空间复杂度o(n^2) 时间复杂度o(n^3)

空间上我们可以进一步优化,不要从1开始存储到n,优化为只存储平方数

java代码

class Solution {
//for example
//n n - 1 n - 2
//dp[n][num] = 1 + mim{dp[n][num - n], dp[n - 1][num - n], dp[n - 2][num - n], ..., dp[1][n]}
//ans = min {dp[k][sum]} k = 1,2,3,...,n-1,n
public int numSquares(int n) {
int ans = Integer.MAX_VALUE;
List<Integer> data = new ArrayList<>();
int i = 0;
for (; i * i <= n; i++) {
data.add(i * i);
}
if (i * i == n) return 1; int cnt = data.size();
int[][] dp = new int[cnt][1 + n];
for (int l = 1; l < cnt; l++) {
for (int p = 1; p <= n; p++) {
dp[l][p] = Integer.MAX_VALUE;
}
} for (int k = 1; k < cnt; k++) {
int val = data.get(k);
for (int sum = val; sum <= n; sum++) {
for (int j = k; j >= 1; j--) {
if (dp[j][sum - val] == Integer.MAX_VALUE) continue;
//System.out.println("k={}" + k + " sum=" + sum + " j={}" + j + " remain={}" + (sum - k));
dp[k][sum] = Math.min(dp[k][sum], 1 + dp[j][sum - val]);
//System.out.println("dp[k][sum]=" + dp[k][sum]);
}
} if (ans > dp[k][n]) {
//System.out.println("dp[k][n]=" + dp[k][n]);
ans = dp[k][n];
}
} return ans;
} public boolean isSquare(int d) {
int i = 1;
for (; i * i < d; i++) {
} if (i * i == d) return true;
return false;
}
}

c++代码

class Solution {
public:
//dp[i][j] = 1 + min{dp[i][j - i], dp[nextI][j - i], ..., dp[k][j]}
//dp[i][i] = 1 + min{dp[0][0]} = 1
//dp[i][j] = 1 + min{dp[i][j - i], dp[ni][j - i], ..., dp[nii][j - i]}
//if i > j, dp[i][j] = INT_MAX;
//if i == j, dp[i][j] = 1;
//if i < j,
//
int numSquares(int n) {
int i = 1;
vector<int> data;
while (i * i <= n) {
data.push_back(i * i);
++i;
} int len = data.size();
int dp[1 + len][1 + n];
memset(dp, 0, sizeof(dp));
int ans = INT_MAX;
//cout<<"len="<<len<<endl; for (int i = 1; i <= len; i++) {
//cout<<"num="<<data[i - 1]<<endl;
for (int j = data[i - 1] - 1; j >= 1; j--) {
dp[i][j] = INT_MAX;
//output(i, j, dp[i][j]);
}
} for (int j = 1; j <= n; j++) {
for (int i = 1; i <= len && data[i - 1] <= j; i++) {
int tmp = INT_MAX;
for (int k = i; k <= len; k++) {
tmp = min(tmp, dp[k][j - data[i - 1]]);
} //output(i, j, tmp); if (tmp != INT_MAX) {
dp[i][j] = 1 + tmp;
} else {
dp[i][j] = tmp;
} //output(i, j, dp[i][j]);
}
} for (int i = 1; i <= len; i++) {
ans = min(ans, dp[i][n]);
//cout<<"ans="<<ans<<endl;
} return ans;
} void output(int i, int j, int tmp) {
cout<<"i="<<i<<" j="<<j<<" tmp="<<tmp<<endl;
} void output2(int i, int j, int tmp) {
cout<<"output2 i="<<i<<" j="<<j<<" tmp="<<tmp<<endl;
}
};

第二种解法: 一维dp

思路: dp[n] = 1 + min{dp[n - i * i]} n - i * i >= 0

想使和为n,则最后一步使用的平方数可以为 1, 或者 4 或者 9, 即最后一步可以使用 i * i

则把所有可能枚举出来,求1 + min{dp[n - i * i]}

java代码

class Solution {
//dp[i] = min{dp[i - j * j]} i - j * j >= 0
public int numSquares(int n) {
List<Integer> dp = new ArrayList<>();
for (int i = 0; i <= n; i++) {
dp.add(Integer.MAX_VALUE);
}
dp.set(0, 0); for (int i = 1; i <= n; i++) {
int j = 1;
while (i - j * j >= 0) {
if (dp.get(i - j * j) != Integer.MAX_VALUE) {
dp.set(i, Math.min(dp.get(i), 1 + dp.get(i - j * j)));
}
++j;
}
} return dp.get(n);
}
}

c++代码

class Solution {
public:
//dp[n] = min{dp[n - i*i]} i*i<=n
//dp[n] represent least number of perfect square numbers
//dp[0] = 0, dp[1] = 1, dp[2] = dp[1] + 1 = 2
int numSquares(int n) {
int dp[1 + n];
for (int i = 0; i < n + 1; i++) {
dp[i] = INT_MAX;
} dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
while (i - j * j >= 0) {
if (dp[i - j * j] != INT_MAX) {
//cout<<dp[i]<<" "<<dp[i - j * j]<<endl;
dp[i] = min(dp[i], 1 + dp[i - j * j]);
//cout<<"dp[i]="<<dp[i]<<endl;
}
++j;
}
} /*
for (int d : dp) {
cout<<d<<endl;
}
*/ return dp[n];
}
};

解题报告-Perfect Squares的更多相关文章

  1. POJ 2002 Squares 解题报告(哈希 开放寻址 & 链式)

    经典好题. 题意是要我们找出所有的正方形.1000点,只有枚举咯. 如图,如果我们知道了正方形A,B的坐标,便可以推测出C,D两点的坐标.反之,遍历所有点作为A,B点,看C,D点是否存在.存在的话正方 ...

  2. USACO Section1.2 Palindromic Squares 解题报告

    palsquare解题报告 —— icedream61 博客园(转载请注明出处)------------------------------------------------------------ ...

  3. Facebook Hacker Cup 2014 Qualification Round 竞赛试题 Square Detector 解题报告

    Facebook Hacker Cup 2014 Qualification Round比赛Square Detector题的解题报告.单击这里打开题目链接(国内访问需要那个,你懂的). 原题如下: ...

  4. poj分类解题报告索引

    图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Jou ...

  5. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  6. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  7. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  8. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  9. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

随机推荐

  1. 解决eclipse maven install 造成JVM 内存溢出(java.lang.OutOfMemoryError: Java heap space)

    maven install 报错信息: The system is out of resources.Consult the following stack trace for details.jav ...

  2. 为什么有logistics函数

    直观地看: 如果是softmax函数,我想有跟多的选择方向吧

  3. CMS初步认识

    一CMS本质 [1]基本思想是:分离内容的管理和设计,页面显示的风格和框架存储在模板里.至于页面显示的内容存储在数据库中或一个独立的文件中.当一个用户请求页面时,各部分联合生成一个标准的 HTML 页 ...

  4. DecimalFormat格式化数字

    DecimalFormat格式化数字 DecimalFormat类也是Format的一个子类,主要作用是格式化数字.当然,在格式化数字时要比直接使用NumberFormat更加 方便,因为可以直接指定 ...

  5. 在css中使用hover来控制其他元素的样式,该两个元素必须是父子元素

    .col-3:hover .check-box { display: block; } 在css中使用hover来控制其他元素的样式,该两个元素必须是父子元素!!!!

  6. linux python 安装 nose lapack atlas numpy scipy

    linux python 安装 nose lapack atlas numpy scipy --http://lib.csdn.net/article/python/1262 作者:maple1149 ...

  7. Linux内核调试

    1.控制台优先级配置cat /proc/sys/kernel/printk6 4 1 76是控制台的优先级,打印信息的优先级要比它高才能打印出.4是默认的优先级cat /var/log/message ...

  8. box2d试用

    下载之后,修改里面的Testbed,加入一个footest,测试一下俺的冰箱能不能放到厨房里面

  9. 移植SDL2.2问题及解决方法

    项目需要ffmpeg+SDL播放视频,所以不得不移植SDL 根据 <移植SDL最新版本>http://blog.csdn.net/flyyang123456789/article/deta ...

  10. keepalive配置db层的ha的一些注意点

    具体db是那种都一样 db先做好replica,可以用自己带的,或者drbd的磁盘复制 db和keepalived必须在同一主机 keepalived里面的rs必须只有一个(否则,做不了主从,理论上会 ...