解题报告-Perfect Squares
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的更多相关文章
- POJ 2002 Squares 解题报告(哈希 开放寻址 & 链式)
		经典好题. 题意是要我们找出所有的正方形.1000点,只有枚举咯. 如图,如果我们知道了正方形A,B的坐标,便可以推测出C,D两点的坐标.反之,遍历所有点作为A,B点,看C,D点是否存在.存在的话正方 ... 
- USACO Section1.2 Palindromic Squares 解题报告
		palsquare解题报告 —— icedream61 博客园(转载请注明出处)------------------------------------------------------------ ... 
- Facebook Hacker Cup 2014 Qualification Round 竞赛试题 Square Detector 解题报告
		Facebook Hacker Cup 2014 Qualification Round比赛Square Detector题的解题报告.单击这里打开题目链接(国内访问需要那个,你懂的). 原题如下: ... 
- poj分类解题报告索引
		图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Jou ... 
- CH Round #56 - 国庆节欢乐赛解题报告
		最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ... 
- 二模13day1解题报告
		二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ... 
- BZOJ 1051 最受欢迎的牛 解题报告
		题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ... 
- 习题:codevs  2822 爱在心中 解题报告
		这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ... 
- 习题:codevs 1035 火车停留解题报告
		本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ... 
随机推荐
- Memcached介绍及相关知识
			memcached简介 1.memcached是一个免费开源的.高性能的,具有分布式内存对象的缓存系统.memcached通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括 ... 
- 分析现有 WPF / Windows Forms 程序能否顺利迁移到 .NET Core 3.0(使用 .NET Core 3.0 Desktop API Analyzer )
			今年五月的 Build 大会上,微软说 .NET Core 3.0 将带来 WPF / Windows Forms 这些桌面应用的支持.当然,是通过 Windows 兼容包(Windows Compa ... 
- flask第二十一篇——练习题
			自定义url转化器 实现一个自定义的URL转换器,这个转换器需要满足的是获取从多少到多少的url,例如,你输入的地址是http://127.0.0.1:8000/1-5/,那么页面返回[1,2,3,4 ... 
- BZOJ3732: Network(Kruskal重构树)
			题意 Link 给出一张$n$个点的无向图,每次询问两点之间边权最大值最小的路径 $n \leqslant 15000, m \leqslant 30000, k \leqslant 20000$ S ... 
- C编译相关
			1,#error在编译期进行警告判断 eg: #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 和条件编译宏一起使用,在编译时就可以 ... 
- Jacoco+Jenkines小白之路
			Jacoco+Jenkines小白之路 最近工作中正在推广jacoco的增量覆盖率的统计,想学习一波,纯粹采坑中,适合小白学习jacoco. 一.代码覆盖率 引入代码覆盖率 : 代码覆盖率是指对现有代 ... 
- C#多线程编程之:异步事件调用
			当一个事件被触发时,订阅该事件的方法将在触发该事件的线程中执行.也就是说,订阅该事件的方法在触发事件的线程中同步执行.由此,存在一个问 题:如果订阅事件的方法执行时间很长,触发事件的线程被阻塞,长时间 ... 
- PHP调用Linux的命令行执行文件压缩命令&&创建文件夹修改权限
			一开始,我和普通青年一样,想到用PHP内置的 ZipArchive纠结的是环境上没安装zip扩展,想采用用PHP调用Linux的命令行 ,执行压缩命令,感兴趣的朋友可以了解下,希望本文对你有所帮助 前 ... 
- python渗透测试工具包
			网络 Scapy, Scapy3k: 发送,嗅探,分析和伪造网络数据包.可用作交互式包处理程序或单独作为一个库.pypcap, Pcapy, pylibpcap: 几个不同 libpcap 捆绑的py ... 
- 读取配置文件工具demo
			//读取配置文件public class ResourcesUtils { /* * @description:根据属性获取文件名 * * @param:propertyName文件的属性名 * * ... 
