代码随想录|动态规划 322. 零钱兑换 279.完全平方数 139.单词拆分

322. 零钱兑换

题目

参考文章

思路:本题其实也是完全背包问题

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

但是在初始化dp数组时,要初始化为最大的值,因为从题目知道,要得到的是最少的硬币个数,所以在取min时,为了防止会被初始值覆盖的风险,得把初始值设置为最大值

递推公式:dp[j]=min(dp[j-conis[i]]+1,dp[j]);

这里为什么是 +1 呢?因为题目是求硬币个数,所以要把当前的硬币加上,就直接加1即可。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

本题不强调排列或组合

代码:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int max=Integer.MAX_VALUE;
        int[] dp=new int[amount+1];
        
        for(int i=0;i<=amount;i++){
            dp[i]=max;
        }

        dp[0]=0;

        for(int i=0;i<coins.length;i++){
            for(int j=coins[i];j<=amount;j++){
                if(dp[j-coins[i]]!=max){//只有当要取的数组值不是最大值,最后得到的最小值才有意义
                    dp[j]=Math.min(dp[j-coins[i]]+1,dp[j]);
                }
            }
        }

        return dp[amount]==max?-1:dp[amount];
    }
}

279.完全平方数

题目

参考文章

思路:本题思路和 322零钱兑换相似。也是求最少数量,仍初始化dp数组为最大值。然后一次次的最最小值。

同时有因为完全平方数中有 1 所以无论什么数,都可以由1拼凑出来

代码:

class Solution {
    public int numSquares(int n) {
        int max=Integer.MAX_VALUE;
        int[] dp=new int[n+1];

        for(int i=0;i<=n;i++){
            dp[i]=max;
        }

        dp[0]=0;

        for(int i=1;i*i<=n;i++){//因为由题目知道,其要的是完全平方数,所以直接把 i*i作为当前的物品,n为背包容量
            for(int j=i*i;j<=n;j++){
                dp[j]=Math.min(dp[j-i*i]+1,dp[j]);
            }
        }


        return dp[n];
    }
}

139.单词拆分

题目

参考文章

思路:单词就是物品,字符串s就是背包

dp数组含义 :dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词

 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true  (j<i)

dp[0]表示如果字符串为空的话,说明出现在字典里

dp[0]=true,其他的为false

本题要求的是排列数,为什么呢?因为在字典集中,同样的单词组,如果顺序变了,它最后得到的字符都是不一样的,所以强调排列数。

排列数(即使是相同元素,但是顺序不同,也作为一个分组)

组合数(把相同元素的都认为只有一个组)

这里j<i,是因为我们后面要取s中从j到i位置的字符是否在set集合中,如果在就表示可以组成,把当前的点改为true

这里的dp[j]其实就是说,前一个单词比较的时候,是确定可以组成一个s的一部分的,才可以设置下一个也可以组成s的一部分,如果dp[j]的时候都不能组成s的一部分,这里即使单词配对正确,也是不能得到s字符串

代码:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> set=new HashSet<>(wordDict);
        boolean[] dp=new boolean[s.length()+1];
        dp[0]=true;

        for(int i=1;i<=s.length();i++){//先遍历背包
            for(int j=0;j<i&&!dp[i];j++){//再遍历物品,这里j<i,是因为我们后面要取s中从j到i位置的字符是否在set集合中,如果在就表示可以组成,把当前的点改为true
                if(set.contains(s.substring(j,i))&&dp[j]){//这里的dp[j]其实就是说,前一个单词比较的时候,是确定可以组成一个s的一部分的,才可以设置下一个也可以组成s的一部分,如果dp[j]的时候都不能组成s的一部分,这里即使单词配对正确,也是不能得到s字符串
                    dp[i]=true;
                }
            }
        }

        return dp[s.length()];
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值