动态规划

这篇博客介绍了如何使用动态规划算法解决三个实际问题:1) 给定工人总数,求解挖掘金矿的最大黄金储量;2) 在无限硬币面额下,找出凑成特定金额所需的最少硬币数量;3) 计算一个字符串中回文子串的总数。通过示例代码详细解析了每个问题的动态规划解决方案,展示了解决这类问题的关键思路和技巧。
摘要由CSDN通过智能技术生成

1.金矿问题

有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。设黄金储量golden = {400, 500, 200, 300, 350},需要参与的工人数为person = {5, 5, 3, 4, 3}。
如果参与挖矿的工人的总数是10。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半的金矿。
要求用程序求出,最多能挖到多少黄金?

public static void main(String[] args) {
        int w = 10;
        int[] person = {5, 5, 3, 4, 3};
        int[] golden = {400, 500, 200, 300, 350};
        System.out.println("最多得到黄金: " + getBestGoldMining(w, person, golden));
    }

    private static int getBestGoldMining(int w, int[] person, int[] golden) {
        int[] dp = new int[w + 1];
        //依次判断每座金矿
        for (int i = 0; i < golden.length; i++) {
            //此处倒序,因为需要用到上一座金矿所产生的dp[j - person[i]]的值
            for (int j = w; j > 0; j--) {
                if (j >= person[i]) {
                    //判断此座金矿挖还是不挖,得到金矿更多
                    dp[j] = Math.max(dp[j], dp[j - person[i]] + golden[i]);
                }
            }
        }
        return dp[w];
    }

2.硬币找零

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

示例 1:

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

示例 2:

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

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

分析:dp(n) = min{dp(n), dp(n - conins[i]) + 1}
此题和金矿问题区别在于,每种硬币的数量是无限的,而金矿数组却是确定的

public static void main(String[] args) {
        int[] coins = {1, 2, 5};
        int amount = 11;
        System.out.println(coinChange(coins, amount));
    }

    private static int coinChange(int[] coins, int amount) {
        if (amount == 0) {
            return 0;
        }
        int[] dp = new int[amount + 1];
        for (int i = 1; i <= amount; i++) {
            //初始化dp[i],注意超出int取值范围
            dp[i] = Integer.MAX_VALUE - 1;
            for (int coin : coins) {
                if (i >= coin) {
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }
        return dp[amount] == Integer.MAX_VALUE - 1 ? -1 : dp[amount];
    }

3.回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同起始索引或结束索引的子字符串即使由相同的字符组成,也会被计为不同的子字符串。

示例1:

输入: “abc”
输出: 3
说明:三个回文串:“a”,“b”,“c”。

示例2:

输入: “aaa”
输出: 6
说明:六个回文串:“a”,“a”,“a”,“aa”,“aa”,“aaa”。

分析:“回文串”是一个正读和反读都一样的字符串。
dp[i] [j] 表示字符串第 i 到 j 位的子串是否为回文串,当字符串第 i 位字符与第 j 位字符相同:
1> j - i = 0,同一个字符;
2> j - i = 1, ‘aa’,重复的两个字符;
3> j - i = 2, ‘aba’,两侧字符相同;
4> dp[i+1][j-1]也是回文串

public static void main(String[] args) {
        String str = "aaa";
        System.out.println(childStrCount(str));
    }

    private static int childStrCount(String str) {
        int length = str.length();
        boolean[][] dp = new boolean[length][length];
        int count = 0;
        //因为判断dp[i][j]需要先判断dp[i + 1][j - 1], 所以i需要倒序,j需要正序遍历
        for (int i = length - 1; i >= 0; i--) {
            for (int j = i; j < length; j++) {
                if (str.charAt(i) == str.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
                    dp[i][j] = true;
                    count++;
                }
            }
        }
        return count;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值