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. BusyBox ifup udhcpc后台运行

    /********************************************************************** * BusyBox ifup udhcpc后台运行 * ...

  2. /dev/mem直接操作硬件寄存器

    /******************************************************************************* * /dev/mem直接操作硬件寄存器 ...

  3. C# 图片生成缩略图

    C# 图片生成缩略图方法: /// <summary> /// 生成缩略图 /// </summary> /// <param name="fileName&q ...

  4. Html页面Dom对象之Event

    HTML DOM Event 对象 实例 哪个鼠标按钮被点击? 光标的坐标是? 被按的按键的 unicode 是? 相对于屏幕,光标的坐标是? shift 键被按了吗? 哪个元素被点击了? 哪个事件类 ...

  5. FastAdmin 是如何利用 Git 管理插件代码的?

    FastAdmin 是如何利用 Git 管理插件代码的? 由于 FastAdmin 的插件很多,如果每一个插件用一个项目来管理,可以倒是可以,但是项目还多了. 但是如果使用文件夹在同一级的的方式又不方 ...

  6. Spring Could与Dubbo、Docker、K8S

    如果你是在一个中小型项目中应用Spring Cloud,那么你不需要太多的改造和适配,就可以实现微服务的基本功能.但是如果是在大型项目中实践微服务,可能会发现需要处理的问题还是比较多,尤其是项目中老代 ...

  7. php生成文字图片效果

    php生成文字图片效果最近看到php的GD功能,试着做了一个基本生成文字图片效果的代码: 显示文字图片页面:demo.php<?php$str = $_REQUEST['str'] ? $_RE ...

  8. CentOS 6安装php加速软件Zend Guard(转)

    (尚未验证) PHP5.3以上的版本不再支持Zend Optimizer,已经被全新的 Zend Guard Loader 取代,下面是安装Zend Guard具体步骤,以下操作均在终端命令行执行 1 ...

  9. UOJ 54 【WC2014】时空穿梭——莫比乌斯反演

    题目:http://uoj.ac/problem/54 想写20分. Subtask 2 就是枚举4个维度的值的比例,可算对于一个比例有多少个值可以选,然后就是组合数.结果好像不对. 因为模数太小,组 ...

  10. 4.Appium实现自动化安装apk

    一.代码如下所示: from appium import webdriver import os apk_path = os.path.abspath(os.path.join(os.path.dir ...