0-1背包问题

本文探讨了动态规划和组合优化在解决编程挑战中的应用,如完全背包问题、硬币找零问题、字符串拆分和组合求和问题。通过四个具体的示例,展示了如何使用这些算法高效地找出最优解。每个示例都详细解释了其背后的动态规划思想,并提供了关键代码实现。
摘要由CSDN通过智能技术生成

class Solution {
    public int coinChange(int[] coins, int amount) {
       
        /**
           因为硬币是可以重复使用的,所以是一个完全背包问题,完全背包问题只需要将0-1背包的逆序遍历dp数组改成正序遍历即可

         */

        if(amount ==0) return 0;

        int[] dp = new int[amount+1];

        for(int coin :coins){
            // 将逆序遍历改成正序遍历
            for(int j = coin;j<=amount;++j){
                if(j == coin){
                    // 如果j恰好等于当前面值coin,那就当前j下要一个硬币coin
                    dp[j] = 1;
                }else if(dp[j] ==0 && dp[j-coin] != 0){dp[j] = dp[j-coin]+1;}
                else if(dp[j-coin] != 0){dp[j] = Math.min(dp[j],dp[j-coin]+1);}

            }
        }
        // 如果amount金额下有满足条件的硬币个数,就返回。否则返回-1
        return dp[amount] == 0 ? -1 :dp[amount];

    }
}

class Solution {
    public int change(int amount, int[] coins) {

        int[] dp = new int[amount+1];

        dp[0] =1;
        for(int coin:coins){
            for(int j =coin;j<=amount;++j){

                // 之前做完全背包问题是比较并只存储一个要么数量最大或最小的个数,这里是全部都要即累加
                dp[j] = dp[j] +dp[j-coin] ;
            }
        }
        return dp[amount];

    }
}

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        /**
            完全背包问题
         */

         int n =  s.length();

         boolean[] dp = new boolean[n+1];

         dp[0] =true;

         // 这里的背包是s字符串,物品是数组中的每一个元素,向背包里面装物品

         for(int i=1;i<=n;++i){  // 外层循环是背包
             for(String word:wordDict){  // 内层循环是物品
                  int len = word.length();
                  if(len<=i && word.equals(s.substring(i-len,i))){  // 表示物品小于背包容量, 对应包的这一部分 i-len,i
                      // 要么装包要么不装
                      dp[i] =   dp[i] || dp[i-len];


                  }

             }
         }
         return dp[n];

    }
}

 

class Solution {
    public int combinationSum4(int[] nums, int target) {

        /**
           完全背包+组合总和
         */

         int[] dp = new int[target+1];
         dp[0] =1;

         Arrays.sort(nums);

         //外层是背包
         for(int i =1;i<= target;++i){
             // 内层是物品,遍历nums找到所有的可能不超过容量i的物品,累加所有能得到的组合
             for(int j=0;j<nums.length && nums[j]<=i ;++j){ //nums[j]<i 当前的物品需要小于容量i,才不会爆仓
                 dp[i] = dp[i] + dp[i-nums[j]] ;//dp[i-nums[j]]  是前序的
             }
         }
         return dp[target];

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zero _s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值