• [Leetcode]279.完全平方数


    最开始的时候,我想到的动态方程很简单,就是

    dp[i]=min(dp[i],dp[i-平方数]+1)

    其中i-平方数一定要大于0要不然就会越界。这个思路很简单,举个例子:

    dp[5]=min(dp[5-12]+1,dp[5-22]+1,dp[5])

    这表示5可以如下组合:

    dp[5] = min(所有组成4的完全平方数+完全平方数1即dp[4]+1, 所有组成1的平方数+完全平方数4即dp[1]+1)

    这个方程在初始化dp[0] ,dp[1],dp[2] 和其他的dp为一个大值之后就非常简单了,只需往MAXN迭代就行了,算法的效率为O(nlog n)

    原始解法:

    class Solution {
    public:
        int numSquares(int n) {
            const int MAXN=10000;
            int dp[MAXN+1];
            memset(dp,0x3f3f3f3f,sizeof(dp));
            dp[0]=0;
            dp[1]=1;
            /*1*1=1*/
            dp[2]=2;
            /*1*1+1*1=2*/
            dp[3]=3;
            /*1*1+1*1+1*1=3*/
            dp[4]=1;
            /*2*2=4*/
            for(int i=5;i<=MAXN;i++){
                for(int j=1;i-j*j>=0;j+=1){
                    dp[i]=min(dp[i],dp[i-j*j]+1);
                }
            }
            return dp[n];
        }
    };
    

    这个算法虽然非常容易实现但效率非常的低,我们依然尝试这个方程,换一个方向去实现。

    这次使用了vector来存储dp数组,目的是为了节省空间。在第二层遍历的时候

    for (int j=1; i+j*j <= n; j++)

    我们通过正向进行遍历算法方便理解。

    代码在执行上比原来的代码要快,但是还是没有改变算法的O(nlog n)的效率

    class Solution {
    public:
        const int MAXN=0x3f3f3f3f;
        int numSquares(int n) {
            vector<int> dp(n+1, MAXN);
            dp[0] = 0;
            for (int i=0; i<=n; i++)
                for (int j=1; i+j*j <= n; j++) {
                    dp[i+j*j] = min(dp[i+j*j], dp[i] + 1);
                }
            return dp.back();
        }
    };
    

    我们看一下最高效的解法,这种解法没有用到动态规划而是用数学的方法解决的。我们枚举答案后发现每一个正数必由1-4个完全平方数,没有超过4。这在数学上又叫做[四平方定理][https://baike.baidu.com/item/四平方和定理]

    即满足四数平方和定理的数n(一定由四个数构成),必定满足n=4^a(8b+7)

    这样我们可以通过定理快速写出如下代码。

    class Solution {
    public:
    int numSquares(int n) {
            // 去除4因子
            while (n % 4 == 0)
                n /= 4;
            // 若除8余7,满足四平方定理,必由4个完全平方数组成
            if (n % 8 == 7)
                return 4;
            // 再尝试将其拆成两个或一个完全平方数
            for (int i=0; i*i <= n; i++) {
                int b = sqrt(n - i*i);
                if (i*i + b*b == n)
                    return !!i + !!b;
            }
            return 3;
      }
    };
    
  • 相关阅读:
    IE 兼容问题笔记
    php编码与解码
    php 一些神奇加有趣的函数
    RESTful 规范
    关于CSS3背景渐变色无效问题
    ECShop
    php中的PHP_EOL换行符
    用 openSSL 生成 公钥 私钥
    app调用支付宝支付 笔记
    utf8 文件 错误保存为gbk 中文乱码 解决方法
  • 原文地址:https://www.cnblogs.com/adamwong/p/10202335.html
Copyright © 2020-2023  润新知