Leetcode-完全平方数

目录

1.题目描述

2.解题思路

3.源代码

4.完全背包问题


1.题目描述

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.

示例2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.

2.解题思路

这个问题就是完全背包问题的简单变种,在这里,平方数sqr就是物品的重量weight,物品产生的价值val都是1。题目问的问题是,能让这m个物品装满空间为n的背包的方法中,产生价值最少的装法,所以把模板里的最大值改成最小值就行。

思路:
标签:动态规划

  1. 首先初始化长度为 n+1 的数组 dp,每个位置都为 0
  2. 如果 n 为 0,则结果为 0
  3. 对数组进行遍历,下标为 i,每次都将当前数字先更新为最大的结果,即 dp[i]=i,比如 i=4,最坏结果为 4=1+1+1+1 即为 4 个数字
  4. 动态转移方程为:dp[i] = MIN(dp[i], dp[i - j * j] + 1),i 表示当前数字,j*j 表示平方数
  5. 时间复杂度:O(n*sqrt(n))O(n∗sqrt(n)),sqrt 为平方根

3.源代码

1.直接套用完全背包的模板进行解题

class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n + 1]; // 默认初始化值都为0
        for (int i = 1; i <= n; i++) {
            dp[i] = i; // 最坏的情况就是每次+1
            for (int j = 1; i - j * j >= 0; j++) { 
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1); // 动态转移方程
            }
        }
        return dp[n];
    }
}

Leetcode运行截图:

 2.将问题分成两个步骤,首先枚举平方数,将平方数存入数组,然后遍历时将平方数当做背包问题的物品的重量。

private   List<Integer>  generateSquareList_1(int  n){
         List<Integer> squareList = new ArrayList<>();
         int  ans=1;
         while(ans*ans<=n) {
             squareList.add(ans * ans);
             ans = ans + 1;
         }
         return  squareList;
}

动态规划

 public int numSquares(int n) {
        int []dp=new  int[n+1];
        dp[0]=0;
        List<Integer>  list=generateSquareList(n);
        for(int i=1;i<=n;i++){
            int min = Integer.MAX_VALUE;
            for(int  num:list){
                    if(num>i){
                         break;
                    }
                min = Math.min(min, dp[i - num] + 1);
            }
            dp[i]=min;
        }
        return dp[n];
    }

运行结果:

提交Leetcode结果截图:

 综合来看,这种方法的综合效率不是很高。

4.完全背包问题

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

 示例2:

输入:coins = [2], amount = 3
输出:-1

 示例3:

输入:coins = [1], amount = 0
输出:0

示例4:

输入:coins = [1], amount = 1
输出:1

解题思路:这个题目就是完全背包的一个变种,总金额amount 就是背包的容量,硬币的coins就是背包的容量。然后我们套用完全背包的模板我们就可以解决问题。

public class Bag_01 {
    public int change(int amount, int[] coins) {
       int  []dp=new int[amount+1];
       //设置初始状态
        dp[0]=1;
        for(int  coin:coins){
            for(int  j=1;j<=amount;j++){
                if(j>=coin){
                     dp[j]=dp[j]+dp[j-coin];
                }
            }
        }
      return dp[amount];
    }
    
      public static void main(String[] args) {
           int  amount=5;
           int []coin={1,2,5};
           Bag_01  b=new Bag_01();
           int ans=b.change(amount,coin);
           System.out.println(ans);

      }
}

运行截图:

Leetcode提交截图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值