【数据结构与算法】(21)高级数据结构与算法设计之 Dynamic-Programming 动态规划算法 代码示例与详细讲解

目录

    • 4.3 Dynamic-Programming
      • 1) Fibonacci
        • 降维
      • 2) 最短路径 - Bellman-Ford
      • 3) 不同路径-Leetcode 62
        • 降维
      • 4) 0-1 背包问题
        • 降维
      • 5) 完全背包问题
        • 降维
      • 6) 零钱兑换问题-Leetcode322
        • 降维
        • 零钱兑换 II-Leetcode 518
      • 7) 钢条切割问题
        • 降维
        • 类似题目 Leetcode-343 整数拆分
      • 8) 最长公共子串
        • 类似题目 Leetcode-718 最长重复子数组
      • 9) 最长公共子序列
        • 最长公共子序列-Leetcode 1143
        • 两个字符串的删除操作-Leetcode 583
      • 10) 最长上升子序列-Leetcode 300
      • 11) Catalan 数
        • Leetcode-96 不同的二叉搜索树
        • Leetcode-22 括号生成
        • 买票找零问题
        • 其它问题
      • 12) 打家劫舍-Leetcode 198
      • 13) Travelling salesman problem
      • 其它题目
        • 组合总和 IV-Leetcode 377

在这里插入图片描述

4.3 Dynamic-Programming

1) Fibonacci

public class Fibonacci {public static void main(String[] args) {System.out.println(fibonacci(13));}public static int fibonacci(int n) {int[] dp = new int[n + 1];dp[0] = 0;dp[1] = 1;if (n < 2) {return dp[n];}for (int i = 2; i <= n; i++) {dp[i] = dp[i - 2] + dp[i - 1];}return dp[n];}
}
降维
public class Fibonacci {public static void main(String[] args) {System.out.println(fibonacci(13));}public static int fibonacci(int n) {        if (n == 0) {return 0;}if (n == 1) {return 1;}int a = 0;int b = 1;for (int i = 2; i <= n; i++) {int c = b + a;a = b;b = c;}return b;}
}

2) 最短路径 - Bellman-Ford

public class BellmanFord {static class Edge {int from;int to;int weight;public Edge(int from, int to, int weight) {this.from = from;this.to = to;this.weight = weight;}}/*f(v) 用来表示从起点出发,到达 v 这个顶点的最短距离初始时f(v) = 0   当 v==起点 时f(v) = ∞   当 v!=起点 时之后新           旧     所有fromf(to) = min(f(to), f(from) + from.weight)from 从哪来to   到哪去f(v4) = min( ∞, f(v3) + 11 ) = 20f(v4) = min( 20, f(v2) + 15 ) = 20v1  v2  v3  v4  v5  v60   ∞   ∞   ∞   ∞   ∞0   7   9   ∞   ∞   14  第一轮0   7   9   20  23  11  第二轮0   7   9   20  20  11  第三轮0   7   9   20  20  11  第四轮0   7   9   20  20  11  第五轮*/public static void main(String[] args) {List<Edge> edges = List.of(new Edge(6, 5, 9),new Edge(4, 5, 6),new Edge(1, 6, 14),new Edge(3, 6, 2),new Edge(3, 4, 11),new Edge(2, 4, 15),new Edge(1, 3, 9),new Edge(1, 2, 7));int[] dp = new int[7]; // 一维数组用来缓存结果dp[1] = 0;for (int i = 2; i < dp.length; i++) {dp[i] = Integer.MAX_VALUE;}print(dp);for (int i = 0; i < 5; i++) {for (Edge e : edges) {if(dp[e.from] != Integer.MAX_VALUE) {dp[e.to] = Integer.min(dp[e.to], dp[e.from] + e.weight);}}}print(dp);}static void print(int[] dp) {System.out.println(Arrays.stream(dp).mapToObj(i -> i == Integer.MAX_VALUE ? "∞" : String.valueOf(i)).collect(Collectors.joining(",", "[", "]")));}
}

3) 不同路径-Leetcode 62

机器人要从左上角走到右下角,每次只能向右向下,问一共有多少条不同路径?

在这里插入图片描述

分析,先考虑较为简单的情况

在这里插入图片描述

可能路径有三种情况:

  • 👉 👇 👇
  • 👇 👇👉
  • 👇👉👇

分析:设坐标为,共有 m 行 n 列

(0,0)	(0,1)
(1,0)	(1,1)
(2,0)	(2,1)

如果终点是 (0,1) 那么只有一种走法

如果终点是 (1,0) 那么也只有一种走法

如果终点是 (1,1) 呢,它的走法是从它的上方走下来,或者从它的左边走过来,因此走法 = (0,1) + (1,0) = 2种

如果终点是 (2,0) 那么也只有一种走法

如果终点是 (2,1) 呢,它的走法是从它的上方走下来,或者从它的左边走过来,因此走法 = (1,1) + (2,0) = 3种

总结规律发现:

  1. 终点是 (0,1) (0,2) (0,3) … (0,n) 走法只有1种
  2. 终点是 (1,0) (2,0) (3,0) … (m,0) 走法也只有1种
  3. 除了上面两种情况以外,(i,j) 处的走法等于(i-1,j) + (i,j-1) 的走法之和,即为递推公式

画表格

0	1	1	1	1	1	1
1	2	3	4	5	6	7
1	3	6	10	15	21	28

题解

public class UniquePaths {public static void main(String[] args) {int count = new UniquePaths().uniquePaths(3, 7);System.out.println(count);}public int uniquePaths(int m, int n) {int[][] dp = new int[m][n];for (int i = 0; i < m; i++) {dp[i][0] = 1;}for (int j = 0; j < n; j++) {dp[0][j] = 1;}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}
}
降维
public class UniquePaths {public static void main(String[] args) {int count = new UniquePaths().uniquePaths(3, 7);System.out.println(count);}public int uniquePaths(int m, int n) {int[] dp = new int[n];Arrays.fill(dp, 1);for (int i = 1; i < m; i++) {dp[0] = 1;for (int j = 1; j < n; j++) {dp[j] = dp[j] + dp[j - 1];}}return dp[n - 1];}
}

类似于不规则的杨辉三角

4) 0-1 背包问题

public class KnapsackProblem {/*1. n个物品都是固体,有重量和价值2. 现在你要取走不超过 10克 的物品3. 每次可以不拿或全拿,问最高价值是多少编号 重量(g)  价值(元)                        简称1   4       1600           黄金一块   400    A2   8       2400           红宝石一粒 300    R3   5       30             白银一块         S0   1       1_000_000      钻石一粒          D1_001_6301_002_400*//*1   2   3   4   5   6   7   8   9   10aa               ra               rd               da          da  dr  dr*/static class Item {int index;String name;int weight;int value;public Item(int index, String name, int weight, int value) {this.index = index;this.name = name;this.weight = weight;this.value = value;}@Overridepublic String toString() {return "Item(" + name + ")";}}public static void main(String[] args) {Item[] items = new Item[]{new Item(1, "黄金", 4, 1600),new Item(2, "宝石", 8, 2400),new Item(3, "白银", 5, 30),new Item(4, "钻石", 1, 10_000),};System.out.println(select(items, 10));}static int select(Item[] items, int total) {int[][] dp = new int[items.length][total + 1];print(dp);Item item0 = items[0];for (int j = 0; j < total + 1; j++) {if (j >= item0.weight) {dp[0][j] = item0.value;}}print(dp);for (int i = 1; i < dp.length; i++) {Item item = items[i];for (int j = 1; j < total + 1; j++) {// x: 上一次同容量背包的最大价值int x = dp[i - 1][j];if (j >= item.weight) {// j-item.weight: 当前背包容量-这次物品重量=剩余背包空间// y: 剩余背包空间能装下的最大价值 + 这次物品价值int y = dp[i - 1][j - item.weight] + item.value;dp[i][j] = Integer.max(x, y);} else {dp[i][j] = x;}}print(dp);}return dp[dp.length - 1][total];}static void print(int[][] dp) {System.out.println("   " + "-".repeat(63));Object[] array = IntStream.range(0, dp[0].length + 1).boxed().toArray();System.out.printf(("%5d ".repeat(dp[0].length)) + "%n", array);for (int[] d : dp) {array = Arrays.stream(d).boxed().toArray();System.out.printf(("%5d ".repeat(d.length)) + "%n", array);}}
}
降维
static int select(Item[] items, int total) {int[] dp = new int[total + 1];for (Item item : items) {for (int j = total; j > 0; j--) {if (j >= item.weight) { // 装得下dp[j] = Integer.max(dp[j], item.value + dp[j - item.weight]);}}System.out.println(Arrays.toString(dp));}return dp[total];
}

注意:内层循环需要倒序,否则 dp[j - item.weight] 的结果会被提前覆盖

5) 完全背包问题

public class KnapsackProblemComplete {static class Item {int index;String name;int weight;int value;public Item(int index, String name, int weight, int value) {this.index = index;this.name = name;this.weight = weight;this.value = value;}@Overridepublic String toString() {return "Item(" + name + ")";}}public static void main(String[] args) {Item[] items = new Item[]{new Item(1, "青铜", 2, 3),    // cnew Item(2, "白银", 3, 4),    // snew Item(3, "黄金", 4, 7),    // a};System.out.println(select(items, 6));}/*0   1   2   3   4   5   61   0   0   c   c   cc  cc  ccc2   0   0   c   s   cc  cs  ccc3   0   0   c   s   a   a   ac*/private static int select(Item[] items, int total) {int[][] dp = new int[items.length][total + 1];Item item0 = items[0];for (int j = 0; j < total + 1; j++) {if (j >= item0.weight) {dp[0][j] = dp[0][j - item0.weight] + item0.value;}}print(dp);for (int i = 1; i < items.length; i++) {Item item = items[i];            for (int j = 1; j < total + 1; j++) {// x: 上一次同容量背包的最大价值int x = dp[i - 1][j];if (j >= item.weight) {// j-item.weight: 当前背包容量-这次物品重量=剩余背包空间// y: 剩余背包空间能装下的最大价值 + 这次物品价值int y = dp[i][j - item.weight] + item.value;dp[i][j] = Integer.max(x, y);} else {dp[i][j] = x;}}print(dp);}return dp[dp.length - 1][total];}static void print(int[][] dp) {System.out.println("   " + "-".repeat(63));Object[] array = IntStream.range(0, dp[0].length + 1).boxed().toArray();System.out.printf(("%5d ".repeat(dp[0].length)) + "%n", array);for (int[] d : dp) {array = Arrays.stream(d).boxed().toArray();System.out.printf(("%5d ".repeat(d.length)) + "%n", array);}}
}
降维
private static int select(Item[] items, int total) {int[] dp = new int[total + 1];for (Item item : items) {for (int j = 0; j < total + 1; j++) {if (j >= item.weight) {dp[j] = Integer.max(dp[j], dp[j - item.weight] + item.value);}}System.out.println(Arrays.toString(dp));}return dp[total];
}

6) 零钱兑换问题-Leetcode322

public class ChangeMakingProblemLeetcode322 {public int coinChange(int[] coins, int amount) {int max = amount + 1;int[][] dp = new int[coins.length][amount + 1];for (int j = 1; j < amount + 1; j++) {if (j >= coins[0]) {dp[0][j] = 1 + dp[0][j - coins[0]];} else {dp[0][j] = max;}}for (int i = 1; i < coins.length; i++) {for (int j = 1; j < amount + 1; j++) {if (j >= coins[i]) {dp[i][j] = Math.min(dp[i - 1][j], 1 + dp[i][j - coins[i]]);} else {dp[i][j] = dp[i - 1][j];}}print(dp);}int r = dp[coins.length - 1][amount];return r > amount ? -1 : r;}public static void main(String[] args) {ChangeMakingProblemLeetcode322 leetcode = new ChangeMakingProblemLeetcode322();int count = leetcode.coinChange(new int[]{1, 2, 5}, 5);
//        int count = leetcode.coinChange(new int[]{25, 10, 5, 1}, 41);
//        int count = leetcode.coinChange(new int[]{2}, 3);
//        int count = leetcode.coinChange(new int[]{15, 10, 1}, 21);System.out.println(count);}static void print(int[][] dp) {System.out.println("-".repeat(18));Object[] array = IntStream.range(0, dp[0].length + 1).boxed().toArray();System.out.printf(("%2d ".repeat(dp[0].length)) + "%n", array);for (int[] d : dp) {array = Arrays.stream(d).boxed().toArray();System.out.printf(("%2d ".repeat(d.length)) + "%n", array);}}
}
降维
public int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1);dp[0] = 0;for (int coin : coins) {for (int j = coin; j < amount + 1; j++) {dp[j] = Math.min(dp[j], 1 + dp[j - coin]);}}int r = dp[amount];return r > amount ? -1 : r;
}
零钱兑换 II-Leetcode 518
public class ChangeMakingProblemLeetcode518 {/*面值    0        1        2        3        4        51    1        1        1        1        1        12    1        1        2        2        3        35    1        1        2        2        3        4面值    0        1        2        31        0        0        02    1        0        1        0*/public int change(int[] coins, int amount) {int[] dp = new int[amount + 1];dp[0] = 1;for (int coin : coins) {for (int j = coin; j < amount + 1; j++) {dp[j] = dp[j] + dp[j - coin];}}return dp[amount];}public static void main(String[] args) {ChangeMakingProblemLeetcode518 leetcode = new ChangeMakingProblemLeetcode518();int count = leetcode.change(new int[]{1, 2, 5}, 5);System.out.println(count);}}

7) 钢条切割问题

public class CutRodProblem {/*1 5 8 90   1   2   3   41       1   11  111 1111(1) (2) (3) (4)2           11  111 11112   21  21122(1) (5) (6) (10)3       1   11  111 11112   21  2113   2231(1) (5) (8) (10)4       1   11  111 11112   21  2113   22314(1) (5) (8) (10)*/static int cut(int[] values, int n) {int[][] dp = new int[values.length][n + 1];for (int i = 1; i < values.length; i++) {int v = values[i];for (int j = 1; j < n + 1; j++) {if (j >= i) {dp[i][j] = Integer.max(dp[i - 1][j], v + dp[i][j - i]);} else {dp[i][j] = dp[i - 1][j];}}print(dp);}return dp[values.length - 1][n];}public static void main(String[] args) {System.out.println(cut(new int[]{0, 1, 5, 8, 9}, 4));}
}
降维
static int cut(int[] values, int n) {int[] dp = new int[n + 1];for (int i = 1; i < values.length; i++) {int v = values[i];for (int j = i; j < n + 1; j++) {dp[j] = Integer.max(dp[j], v + dp[j - i]);}System.out.println(Arrays.toString(dp));}return dp[n];
}

本质上是完全背包问题,把钢条总长度看作背包容量,切分后的钢条看作物品。只是

  • 此时的背包容量=物品数量,例如,钢条总长度为4,可以看作有四种物品:

    • 长度1的钢条

    • 长度2的钢条

    • 长度3的钢条

    • 长度4的钢条

  • 另外,这个场景下,总能装满背包

类似题目 Leetcode-343 整数拆分
public class Leetcode343 {/*0   1   2   3   41   1   1   11  111 11112   1   1   11  111 11112   21  21122(1) (2) (2) (4)3   1   1   11  111 11112   21  2113   2231(1) (2) (3) (4)4   1   1   11  111 11112   21  2113   22314(1) (2) (3) (4)*/public int integerBreak(int n) {int[] dp = new int[n + 1];Arrays.fill(dp, 1);dp[0] = 1;for (int i = 1; i < n; i++) {for (int j = 0; j < n + 1; j++) {if (j >= i) {dp[j] = Integer.max(dp[j], i * dp[j - i]);}}System.out.println(Arrays.toString(dp));}return dp[n];}public int integerBreak2(int n) {int[][] dp = new int[n][n + 1];Arrays.fill(dp[0], 1);for (int i = 1; i < n; i++) {dp[i][0] = 1;}for (int i = 1; i < n; i++) {for (int j = 0; j < n + 1; j++) {if (j >= i) {dp[i][j] = Integer.max(dp[i - 1][j], i * dp[i][j - i]);} else {dp[i][j] = dp[i - 1][j];}}print(dp);}return dp[n - 1][n];}public static void main(String[] args) {Leetcode343 code = new Leetcode343();System.out.println(code.integerBreak(4));System.out.println(code.integerBreak(10));}
}

8) 最长公共子串

public class LCSubstring {static int lcs(String a, String b) {int[][] dp = new int[b.length()][a.length()];int max = 0;for (int i = 0; i < b.length(); i++) {for (int j = 0; j < a.length(); j++) {if (a.charAt(j) == b.charAt(i)) {if (i == 0 || j == 0) {dp[i][j] = 1;} else {dp[i][j] = dp[i - 1][j - 1] + 1;}max = Integer.max(dp[i][j], max);} else {dp[i][j] = 0;}}}print(dp, a, b);return max;}static void print(int[][] dp, String a, String b) {System.out.println("-".repeat(23));Object[] array = a.chars().mapToObj(i -> String.valueOf((char) i)).toArray();System.out.printf("  "+"%2s ".repeat(a.length()) + "%n", array);for (int i = 0; i < b.length(); i++) {int[] d = dp[i];array = Arrays.stream(d).boxed().toArray();System.out.printf(b.charAt(i) + " " + "%2d ".repeat(d.length) + "%n", array);}}/*i   t   h   e   i   m   at  0   1   0   0   0   0   0h  0   0   2   0   0   0   0e  0   0   0   3   0   0   0n  0   0   0   0   0   0   0*/public static void main(String[] args) {System.out.println(lcs("itheima", "then"));}
}
类似题目 Leetcode-718 最长重复子数组
public class Leetcode718 {public int findLength(int[] nums1, int[] nums2) {int m = nums1.length + 1;int n = nums2.length + 1;int[] dp = new int[n];int max = 0;for (int i = 1; i < m; i++) {for (int j = n - 1; j > 0; j--) {if (nums1[i - 1] == nums2[j - 1]) {dp[j] = dp[j - 1] + 1;max = Integer.max(max, dp[j]);} else {dp[j] = 0;}}}return max;}public int findLength1(int[] nums1, int[] nums2) {int m = nums1.length;int n = nums2.length;int[] dp = new int[n];int max = 0;for (int i = 0; i < m; i++) {for (int j = n - 1; j >= 0; j--) {if (nums1[i] == nums2[j]) {if (i == 0 || j == 0) {dp[j] = 1;} else {dp[j] = dp[j - 1] + 1;}max = Integer.max(max, dp[j]);} else {dp[j] = 0;}}}return max;}public int findLength2(int[] nums1, int[] nums2) {int[][] dp = new int[nums1.length][nums2.length];int max = 0;for (int i = 0; i < nums1.length; i++) {for (int j = 0; j < nums2.length; j++) {if (nums1[i] == nums2[j]) {if (i == 0 || j == 0) {dp[i][j] = 1;} else {dp[i][j] = dp[i - 1][j - 1] + 1;}max = Integer.max(max, dp[i][j]);} else {dp[i][j] = 0;}}}return max;}public static void main(String[] args) {Leetcode718 code = new Leetcode718();System.out.println(code.findLength(new int[]{1, 2, 3, 2, 1}, new int[]{3, 2, 1, 4, 7}));System.out.println(code.findLength(new int[]{1, 0, 0, 0, 1}, new int[]{1, 0, 0, 1, 1}));}
}

9) 最长公共子序列

最长公共子序列-Leetcode 1143
public class LCSubsequence {public int longestCommonSubsequence(String text1, String text2) {int m = text1.length();int n = text2.length();int[][] dp = new int[m + 1][n + 1];for (int i = 1; i < m + 1; i++) {char a = text1.charAt(i - 1);for (int j = 1; j < n + 1; j++) {char b = text2.charAt(j - 1);if (a == b) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = Integer.max(dp[i - 1][j], dp[i][j - 1]);}}}print(dp, text2, text1);return dp[m][n];}static void print(int[][] dp, String a, String b) {System.out.println("-".repeat(23));Object[] array = a.chars().mapToObj(i -> String.valueOf((char) i)).toArray();System.out.printf("     " + "%2s ".repeat(a.length()) + "%n", array);for (int i = 0; i < b.length(); i++) {int[] d = dp[i + 1];array = Arrays.stream(d).boxed().toArray();System.out.printf(b.charAt(i) + " " + "%2d ".repeat(d.length) + "%n", array);}}public static void main(String[] args) {LCSubsequence code = new LCSubsequence();System.out.println(code.longestCommonSubsequence("abcde", "ace"));System.out.println(code.longestCommonSubsequence("ba", "yby"));}
}
两个字符串的删除操作-Leetcode 583
public class Leetcode538 {public static void main(String[] args) {Leetcode538 code = new Leetcode538();System.out.println(code.minDistance("leetcode", "etco"));  // 4System.out.println(code.minDistance("eat", "sea"));		   // 2System.out.println(code.minDistance("park", "spake"));	   // 3}public int minDistance(String word1, String word2) {int m = word1.length();int n = word2.length();char[] chars1 = word1.toCharArray();char[] chars2 = word2.toCharArray();int[][] dp = new int[m + 1][n + 1];for (int i = 1; i < m + 1; i++) {int x = chars1[i - 1];for (int j = 1; j < n + 1; j++) {int y = chars2[j - 1];if (x == y) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = Integer.max(dp[i - 1][j], dp[i][j - 1]);}}}return m + n - dp[m][n] - dp[m][n];}
}

10) 最长上升子序列-Leetcode 300

public class Leetcode300 {/*1       2       3       41       3       6       4       91       13      16      14      19136     134     13916913691491349(1)    (2)      (3)     (3)      (4)4*/public int lengthOfLIS(int[] nums) {int[] dp = new int[nums.length];Arrays.fill(dp, 1);for (int i = 1; i < nums.length; i++) {for (int j = 0; j < i; j++) {if (nums[i] > nums[j]) { // 满足了升序条件// 用之前递增子序列的最大长度 + 1 更新当前长度dp[i] = Integer.max(dp[i], dp[j] + 1);}}System.out.println(Arrays.toString(dp));}return Arrays.stream(dp).max().getAsInt();}public static void main(String[] args) {Leetcode300 code = new Leetcode300();System.out.println(code.lengthOfLIS(new int[]{1, 3, 6, 4, 9}));
//        System.out.println(code.lengthOfLIS(new int[]{10, 9, 2, 5, 3, 7, 101, 18}));
//        System.out.println(code.lengthOfLIS(new int[]{1, 3, 6, 7, 9, 4, 10, 5, 6}));//                                            1 3 6 7 9 10  = 6//                                            1 3 4 5 6     = 5
//        System.out.println(code.lengthOfLIS(new int[]{0, 1, 0, 3, 2, 3}));
//        System.out.println(code.lengthOfLIS(new int[]{7, 7, 7, 7, 7, 7, 7}));}
}

11) Catalan 数

public class Catalan {public static void main(String[] args) {System.out.println(catalan(6));}static int catalan(int n) {int[] dp = new int[n + 1];dp[0] = 1;dp[1] = 1;for (int i = 2; i < n + 1; i++) {for (int j = 0; j < i; j++) {System.out.print("(" + j + " " + (i - 1 - j) + ")\t");dp[i] += dp[j] * dp[i - 1 - j];}System.out.println();System.out.println(Arrays.toString(dp));}return dp[n];}
}
Leetcode-96 不同的二叉搜索树
class Solution {public int numTrees(int n) {int[] dp = new int[n + 1];dp[0] = 1;dp[1] = 1;for (int j = 2; j < n + 1; j++) {for (int i = 0; i < j; i++) { dp[j] += dp[i] * dp[j - 1 - i];}}return dp[n];}
}
Leetcode-22 括号生成
public class Leetcode22 {public List<String> generateParenthesis(int n) {ArrayList<String>[] dp = new ArrayList[n + 1];dp[0] = new ArrayList<>(List.of(""));dp[1] = new ArrayList<>(List.of("()"));for (int j = 2; j < n + 1; j++) {dp[j] = new ArrayList<>();for (int i = 0; i < j; i++) { // 第j个卡特兰数的拆分System.out.printf("(%d,%d)\t", i, j - 1 - i);
//                dp[j] += dp[i] * dp[j - 1 - i];
//                dp[j].add("(" + dp[i] + ")" + dp[j - 1 - i]);for (String k1 : dp[i]) {for (String k2 : dp[j - 1 - i]) {dp[j].add("(" + k1 + ")" + k2);}}}System.out.println(dp[j]);}return dp[n];}public static void main(String[] args) {Leetcode22 code = new Leetcode22();System.out.println(code.generateParenthesis(4));}
}
买票找零问题

售票处售卖球票,每张票 50 元。有2n人前来买票

  • 其中一半人手持 50 元钞票
  • 另一半人手持 100 元钞票

若售票处开始没有任何零钱,问:有多少种排队方式,能够让售票顺畅进行。

思路:

  • 把手持 50 元钞票的人视为左括号
  • 把手持 100 元钞票的人视为右括号
  • 左右括号合法配对,即先出现左括号,再出现右括号,就可以让售票顺畅执行

可以看到,问题又变成了求解 n 的卡特兰数

其它问题
题号标题
Leetcode 331验证二叉树的前序序列化
Leetcode 894所有可能的满二叉树

12) 打家劫舍-Leetcode 198

public class HouseRobberLeetcode198 {/*房子价值0   1   2   3   42   7   9   3   10   1   2   3   40   0   0   0   02   7   11  10  120   1   2   32   1   1   20   1   2   32   2   3   4*/public int rob(int[] nums) {int len = nums.length;if (len == 1) {return nums[0];}int[] dp = new int[len];dp[0] = nums[0];dp[1] = Integer.max(nums[0], nums[1]);for (int i = 2; i < len; i++) {dp[i] = Integer.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[len - 1];}public static void main(String[] args) {HouseRobberLeetcode198 code = new HouseRobberLeetcode198();System.out.println(code.rob(new int[]{2, 7, 9, 3, 1}));System.out.println(code.rob(new int[]{2, 1, 1, 2}));}
}

13) Travelling salesman problem

旅行商问题

在这里插入图片描述

java 代码

public class TravellingSalesmanProblem {/*0   1   2   30   0   1   2   31   1   0   6   42   2   6   0   53   3   4   5   0d(0,{1,2,3}) => c01+d(1,{2,3}) => c12+d(2,{3}) => c23+d(3,{})c13+d(3,{2}) => c32+d(2,{})c02+d(2,{1,3}) => c21+d(1,{3}) => c13+d(3,{})c23+d(3,{1}) => c31+d(1,{})c03+d(3,{1,2}) => c31+d(1,{2}) => c12+d(2,{})c32+d(2,{1}) => c21+d(1,{})d(0,{1}) => c01+d(1,{}) 0->1->0d(1,{1})d(2,{1}) => c21+d(1,{}) 2->1->0d(3,{1}) => c31+d(1,{}) 3->1->0d(0,{2}) => c02+d(2,{}) 0->2->0d(1,{2}) => c12+d(2,{}) 1->2->0d(2,{2})d(3,{2}) => c32+d(2,{}) 3->2->0d(0,{1,2}) => c01+d(1,{2}) => 0->1->2->0c02+d(2,{1}) => 0->2->1->0d(3,{1,2}) => c31+d(1,{2}) => 3->1->2->0c32+d(2,{1}) => 3->2->1->0d(0,{3}) => c03+d(3,{}) 0->3->0d(1,{3}) => c13+d(3,{}) 1->3->0d(2,{3}) => c23+d(3,{}) 2->3->0d(3,{3})d(0,{1,3}) => c01+d(1,{3}) => 0->1->3->0c03+d(3,{1}) => 0->3->1->0d(2,{1,3}) => c21+d(1,{3}) => 2->1->3->0c23+d(3,{1}) => 2->3->1->0d(0,{2,3}) => c02+d(2,{3}) => 0->2->3->0c03+d(3,{2}) => 0->3->2->0d(1,{2,3}) => c12+d(2,{3}) => 1->2->3->0c13+d(3,{2}) => 1->3->2->0d(0,{1,2,3}) => c01+d(1,{2,3})  11+1c02+d(2,{1,3})  10+2c03+d(3,{1,2})  12+30       1       2       12      3       13      23      1230       1       2       3       4       5       6       70    0       2       4       9       6       8       10      121    1       _       8       _       7       _       11      _2    2       7       _       _       8       10      _       _3    3       5       7       12      _       _       _       _*/public static void main(String[] args) {int[][] graph = {{0, 1, 2, 3},{1, 0, 6, 4},{2, 6, 0, 5},{3, 4, 5, 0},};
//        System.out.println(tsp(graph));System.out.println(6 >> (0-1));}static int tsp1(int[][] graph) {int n = graph.length;int[][] dp = new int[1 << n][n];for (int[] row : dp) {Arrays.fill(row, Integer.MAX_VALUE / 2);}dp[1][0] = 0;for (int mask = 1; mask < 1 << n; mask++) {for (int i = 0; i < n; i++) {if ((mask & 1 << i) == 0) continue;for (int j = 0; j < n; j++) {if ((mask & 1 << j) != 0) continue;dp[mask | 1 << j][j] = Math.min(dp[mask | 1 << j][j], dp[mask][i] + graph[i][j]);}}print(dp);}int res = Integer.MAX_VALUE;for (int i = 0; i < n; i++) {res = Math.min(res, dp[(1 << n) - 1][i] + graph[i][0]);}return res;}/*110 是否包含 0 = 0 & 1 = 0110 是否包含 1 = 110 & 1 = 0110 是否包含 2 = 11 & 1 = 1110 是否包含 3 = 1 & 1 = 1110 是否包含 4 = 0 & 1 = 0*/static boolean contains(int set, int city) {return (set >> (city - 1) & 1) == 1;}/*110     110^100    ^010----    ----10     100*/static int exclude(int set, int city) {return set ^ (1 << (city - 1));}static int tsp(int[][] g) {int n = g.length;int m = 1 << (n - 1);int[][] dp = new int[n][m];for (int i = 0; i < n; i++) {dp[i][0] = g[i][0];}for (int j = 1; j < m; j++) {for (int i = 0; i < n; i++) {dp[i][j] = Integer.MAX_VALUE / 2;if (contains(j, i)) continue;for (int k = 1; k < n; k++) {if (contains(j, k)) {
//                    System.out.println("(" + k + "," + (j ^ (1 << (k - 1))) + ")");dp[i][j] = Math.min(dp[i][j], g[i][k] + dp[k][exclude(j, k)]);}}}print(dp);}return dp[0][m - 1];}static void print(int[][] dist) {System.out.println("-------------------------");for (int[] row : dist) {System.out.println(Arrays.stream(row).boxed().map(x -> x >= Integer.MAX_VALUE / 2 ? "∞" : String.valueOf(x)).map(s -> String.format("%2s", s)).collect(Collectors.joining(",", "[", "]")));}}
}

其它题目

题号标题
集合覆盖问题
扔鸡蛋问题
Leetcode 72编辑距离
Leetcode 121买股票的最佳时机
组合总和 IV-Leetcode 377

不要被题目名字误导了,本题类似于零钱兑换518题,区别在于零钱兑换求的是组合数,本题求的是排列数

public class CombinationLeetcode377 {static int combinationSum4(int[] nums, int target) {return change(nums, target);}/*0       1       2       3       4 总金额1           1       11      111     11112           1       11      111     11112       12      11221      121222113           1       11      111     11112       12      11221      1213       132112231面值dp[j] = dp[j-1] + dp[j-2] + dp[j-3]*/static int change(int[] coins, int amount) {int[] dp = new int[amount + 1];dp[0] = 1;for (int j = 1; j < amount + 1; j++) {for (int coin : coins) {if (j >= coin) {dp[j] += dp[j - coin];}}System.out.println(Arrays.toString(dp));}return dp[amount];}public static void main(String[] args) {System.out.println(combinationSum4(new int[]{1, 2, 3}, 4));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/491180.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

153.寻找旋转排序数组中的最小值(二分查找)

一、题目 . - 力扣&#xff08;LeetCode&#xff09; 153. 寻找旋转排序数组中的最小值 二、代码 class Solution { public:int findMin(vector<int>& nums) {int left 0;int right nums.size()-1;int mid (leftright)/2;while(left<right){if(nums[mid]>…

C语言里面的内存函数

1.memcpy函数 &#xff08;1&#xff09;函数的模拟实现&#xff0c;这个函数的作用就是把arr1拷贝到arr2里面&#xff0c;单位是字节&#xff0c;20字节就是5整 数&#xff0c;所以输出的就是1234500000&#xff1b; &#xff08;2&#xff09;之所以强制类型转换成为char*是…

【Python笔记-设计模式】前端控制器模式

一、说明 常作为MVC&#xff08;Model-View-Controller&#xff09;模式的一部分&#xff0c;用来处理用户请求并将其分发给相应的处理程序&#xff08;即路由匹配&#xff09;。 (一) 解决问题 将请求的处理流程集中管理&#xff0c;统一处理所有的请求 (二) 使用场景 需…

JS基础(三)-操作和流程控制

一 操作网页元素的步骤 1. 查找网页元素 给标签设置id属性&#xff0c;一个网页中的id值不允许重复 <button id"btn">按钮</button> 2. 给按钮绑定事件&#xff0c;监听用户操作 btn.onclick function(){ 一旦监听到用户的…

matlab一维二维和三维RBF插值方法

1、内容简介 略 50-可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 matlab一维二维和三维RBF插值方法_哔哩哔哩_bilibili 4、参考论文 略

python print 格式化输出详解

print 输出字符串和数字 以下实例中列举了print打印各种类型的示例 示例如下, print("qayrup") # 直接输出字符串print(100) # 输出数字str qayrup print(str) # 输出变量L [1,2,a] # 输出列表类型变量 print(L) t (1,2,a…

【C语言】指针初阶

正文开始之前&#xff0c;我们要记住一个东西就是&#xff1a;地址指针 目录 一、指针的解释二、指针变量和地址1、取地址操作符2、指针变量和解引用操作1、指针变量2、拆解指针类型3、解引用操作符4、注意事项 3、指针变量的大小4、指针的解引用5、void*指针 三、指针的运算1、…

鸿蒙开发【WebGL】简单了解

WebGL的全称为Web Graphic Library(网页图形库)&#xff0c;主要用于交互式渲染2D图形和3D图形。目前HarmonyOS中使用的WebGL是基于OpenGL裁剪的OpenGL ES&#xff0c;可以在HTML5的canvas元素对象中使用&#xff0c;无需使用插件&#xff0c;支持跨平台。WebGL程序是由JavaScr…

Linux多线程服务端编程:使用muduo C++网络库 学习笔记 第十二章 C++经验谈(一)

作者对C的基本态度是“练从难处练&#xff0c;用从易处用”&#xff0c;因此本章有几节“负面”的内容。作者坚信软件开发一定要时刻注意减少不必要的复杂度&#xff0c;一些花团锦簇的招式玩不好反倒会伤到自己。作为应用程序的开发者&#xff0c;对技术的运用要明智&#xff…

如何在C++中实现文件操作

大家好&#xff0c;今天给大家介绍如何在C中实现文件操作&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 在C中&#xff0c;实现文件操作主要涉及到 <fstream> 库&#xf…

[C++]虚函数用法

讲虚函数之前先讲讲面向对象的三大特性&#xff1a;封装、继承、多态。 1、封装 封装是指将数据&#xff08;属性&#xff09;和操作数据的方法&#xff08;函数&#xff09;封装在一个单元中&#xff0c;这个单元就是类。封装的主要目的是隐藏类的内部实现细节&#xff0c;只…

迪萧科技有限公司邀您参观2024生物发酵展

参展企业介绍 浙江迪萧科技有限公司位于浙江杭州&#xff0c;是一家专注于膜技术的国家高新企业。公司针对食品饮料、医药保健等领域的过程分离与控制、产品提取及浓缩、废料资源化利用等提供全方案解决服务。坚持以“顾客至上、优质服务、卓越品质”为原则。为客户企业提供清…