动态规划 ---- 找零钱,最长公共子列

现存人民币面额 【1, 2, 5, 10】,要找零N元,问最少需要多少张人民币?

N为1,最少需要1张。f(1) = 1

N为2,最少需要1张。f(2) = 1

N为3,最少需要2张。f(3) = 2

N为4,最少需要2张。f(4) =  2

N为5,最少需要1张。f(5) = 1

N为6,最少需要2张。f(6) = 2

N为7,最少需要2张。f(7) = 2

N为8,最少需要3张。f(8) =  3

N为9,最少需要3张。f(9) = 3

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

思路:

当N为2时   

               1张2元   f(2) = 1      需要1张

当N为3时 

                  1张2元  + 1元最少组合   需要2张:     f(2) + f(1)  =  2

                  1张1元  + 2元最少组合   需要2张:     f(1) + f(2)  =  2

当N为4时 

                  1张2元  + 2元最少组合   需要2张:     f(2) + f(3)  =  2

                  1张1元  + 3元最少组合   需要2张:     f(1) + f(3)  =  3

                  取最小值2张

当N为5时 

                  1张5元    f(5) = 1      需要1张

.。。。。。。

当N为9时  

                  1张10元 + ?     不满足条件:   f(10) + ?              -------  不满足条件

                  1张5元 + 4元最少组合     需要3张:f(5) + f(4)  = 1 + 2 = 3     ------------     5 + (2 + 2)           4最少2张

                  1张2元 + 7元最少组合     需要3张:f(2) + f(7)  = 1 + 2 = 3     ------------     2 + (2 + 5)           7最少2张

                  1张1元 + 8元最少组合      需要4张:f(1) + f(8)  = 1 + 3 = 4     ------------     1 + (1 + 2 + 5)     8最少3张  
                 取最小值3张

public class Application {
    public static void main(String[] args) {
        int[] table = {1, 2, 5};
        System.out.println(split(5, table));
    }

    static int split(int total, int[] table) {
        int[] result = new int[total + 1];
        Arrays.fill(result, Integer.MAX_VALUE);
        for (int i = 1; i <= total; i++) {
            for (int j = table.length - 1; j >= 0; j--) {
                if (table[j] > i) {  // 找零1,面值5
                    continue;
                }
                if (table[j] == i) {  // 找零5,面值5. 1张就够了
                    result[i] = 1;
                    break;
                }
                int r = i - table[j];  // 找零9 - 面值5  = 剩余4
                int rNum = 1 + result[r];  // 1(面值5一张) + 剩余4的最优解数
                result[i] = Math.min(result[i], rNum);
            }
        }
        return result[total];
    }
}

--------------------------------------------------------------

找零N元,总共有多少种方法?

public class Application {

    public static void main(String[] args) {
        int[] table = {1, 2, 5};
        System.out.println(total(5, table));
    }

    /**
     * for循环   k=1   k从1开始 。 结果为列之和
     *                          0元,1元,2元,3元,4元,5元
     * 组合中包含1且都小于等于1   [0,  1,  1,   1,  1,  1]
     * 组合中包含2且都小于等于2   [0,  0,  1,   1,  2,  2]
     * 组合中包含5且都小于等于5   [0,  0,  0,   0,  0,  1]
     * ----------------------------------------
     * for循环   k=0   k从0开始。 结果为列最后一个(已求和)。
     *                    0元,1元,2元,3元,4元,5元
     * 组合中面值小于等于1  [0,  1,  1,   1,  1,  1]
     * 组合中面值小于等于2  [0,  1,  2,   2,  3,  3]
     * 组合中面值小于等于5  [0,  1,  2,   2,  3,  4]
     * @param money
     * @param table
     * @return
     */
    static int total(int money, int[] table) {
        int[][] dp = new int[table.length][money + 1];
        for (int i = 0; i < table.length; i++) {  //table[i]为对应的面值
            for (int j = 1; j < money + 1; j++) {  // j表示找零数
                for (int k = 0; k * table[i] <= j; k++) { // 包含k张同种钱币,面值table[i]
                    if (k * table[i] == j) {  // k张同种钱币恰好找零
                        dp[i][j] += 1;
                    } else {
                        if (i > 0) {
                            // (零钱总数 - k张面值table[i])的组合数,说明:(i-1)表示面值小于table[i]
                            dp[i][j] += dp[i - 1][j - k * table[i]];
                        }
                    }
                }
            }
        }
        return dp[table.length - 1][money];
    }
}

---------------------------------------------------------------

最长公共子列

public class Application {
    public static void main(String[] args) {
        String a = "dbabcdfe";
        String b = "cabcdc";

        System.out.println(lcs(a, b));
    }

    /**
     *   a = "dbabcdfe";
     *   b = "cabcdc";
     *   a[2] = b[1]     dp[2][1] = 1 = 1
     *   a[3] = b[2]     dp[3][2] = dp[2][1] + 1 = 2
     *   a[4] = b[3]     dp[4][6] = dp[3][2] + 1 = 3
     *   a[5] = b[4]     dp[5][4] = dp[3][2] + 1 = 4
     *   
     * [0, 0, 0, 0, 1, 0]
     * [0, 0, 1, 0, 0, 0]
     * [0, 1, 0, 0, 0, 0]
     * [0, 0, 2, 0, 0, 0]
     * [1, 0, 0, 3, 0, 1]
     * [0, 0, 0, 0, 4, 0]
     * [0, 0, 0, 0, 0, 0]
     * [0, 0, 0, 0, 0, 0]
     * @param a
     * @param b
     * @return
     */
    static String lcs(String a, String b) {
        int[][] dp = new int[a.length()][b.length()];
        for (int i = 0; i < a.length(); i++) {
            for (int j = 0; j < b.length(); j++) {
                if (a.charAt(i) == b.charAt(j)) {
                    if (i > 0 && j > 0) {
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    } else {
                        dp[i][j] = 1;
                    }
                }
            }
        }
        int x = 0;
        int len = 0;
        for (int i = 0; i < dp.length; i++) {         // 从表中查找最大值
            System.out.println(Arrays.toString(dp[i]));
            for (int j = 0; j < dp[i].length; j++) {
                if (len < dp[i][j]) {
                    len = dp[i][j];
                    x = i;
                }
            }
        }
        return a.substring(x + 1 - len, x + 1);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值