【算法笔记】动态规划篇,完全平方数(完全背包、四平方和定理)

完全平方数

动态规划法(原始版)

举例:

  • dp[12]=dp[9]+dp[3]
    • dp[9]=1
    • dp[3]=dp[1]+dp[2]
      • dp[1]=1
      • dp[2]=dp[1]+dp[1]=2
  • dp[12]=dp[4]+dp[8]
    • dp[4] =1
    • dp[8]=dp[4]+dp[4]=2
  1. 定义dp数组,dp[i]表示i可以由最少几个完全平方数表示
  2. 初始化,dp[i*i]=1,完全平方数都可以由自己 1个数表示
  3. 递推公式,从举例中我们可以看到,dp[12]=dp[9]+dp[3],如果我们从小往大了遍历,那dp[9]和dp[3]其实已经知道了,不用再重复计算。
  4. 遍历,假如是 n = 12 n=12 n=12,dp[12]=dp[j]+dp[i-j],比如 d p [ 12 ] = d p [ 1 ] + d p [ 11 ] dp[12]=dp[1]+dp[11] dp[12]=dp[1]+dp[11],一直遍历到 i = = i − j i==i-j i==ijdp[12]=dp[6]+dp[6],因为再往后遍历会重复, d p [ 12 ] = d p [ 11 ] + d p [ 1 ] dp[12]=dp[11]+dp[1] dp[12]=dp[11]+dp[1]
  5. 手写一遍 n = 12 n=12 n=12这种情况
public static int numSquares(int n) {
    int[]dp=new int[n+1];
    for (int i = 1; i < n+1; i++) {
        dp[i]=i;
    }
    for(int i=1;i*i<n+1;i++){
        dp[i*i]=1;
    }
    for(int i=2;i<=n;++i){
        for(int j=1;j<=i-j;j++){
            dp[i]=Math.min(dp[i],dp[j]+dp[i-j]);
        }
    }
    return dp[n];
}

完全背包

物品:每个完全平方数(可以拿好几次)

public int numSquares(int n) {
    List<Integer> nums = new ArrayList();
    for (int i = 1; i * i <= n; ++i) nums.add(i * i);   // 把可选的物品算出来
    int[] dp = new int[n + 1];
    Arrays.fill(dp, n + 1);
    dp[0] = 0;
    for (int i = 0; i < nums.size(); ++i) {
        for (int j = nums.get(i); j < n + 1; ++j) {
            dp[j] = Math.min(dp[j], dp[j - nums.get(i)] + 1);
        }
    }
    return dp[n];
}

四平方和定理

任意一个正整数都可以用最多四个完全平方数表示
也就是返回值只可能为 1、2、3、4
如果n为完全平方数则返回
如果n满足条件: n = 4 k × ( 8 m + 7 ) n=4^k\times(8m+7) n=4k×(8m+7),则返回4
如果n减去一个完全平方数 得一个完全平方数: n − b 2 = a 2 n-b^2=a^2 nb2=a2,则返回2
不满足以上三种条件则返回3

public int numSquares(int n) {
    if (isPerfectSquare(n)) {
        return 1;
    }
    if (checkAnswer4(n)) {
        return 4;
    }
    for (int i = 1; i * i <= n; i++) {
        int j = n - i * i;
        if (isPerfectSquare(j)) {
            return 2;
        }
    }
    return 3;
}

// 判断是否为完全平方数
public boolean isPerfectSquare(int x) {
    int y = (int) Math.sqrt(x);
    return y * y == x;
}

// 判断是否能表示为 4^k*(8m+7)
public boolean checkAnswer4(int x) {
    while (x % 4 == 0) {
        x /= 4;
    }
    return x % 8 == 7;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值