【数据结构与算法】(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.mzph.cn/news/702408.shtml

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

相关文章

python 基础知识点(蓝桥杯python科目个人复习计划51)

今日复习计划&#xff1a;做复习题 例题1&#xff1a;大石头的搬运工 问题描述&#xff1a; 在一款名为“大石头的搬运工”的游戏中&#xff0c;玩家需要 操作一排n堆石头&#xff0c;进行n - 1轮游戏。 每一轮&#xff0c;玩家可以选择一堆石头&#xff0c;并将其移动到任…

【生活】浅浅记录

各位小伙伴们好鸭&#xff0c;今天不是技术文章&#xff0c;浅浅记录一下最近几个月的收获&#x1f60a; 新的一年&#xff0c;一起努力&#xff0c;加油加油&#xff01;

tinymce问题处理

Vite构建工具下Tinymce踩坑指南 解决方案是在路劲前面增加/&#xff0c;这个跟上面链接有些区别&#xff0c;区别原因应该是如果路由采用的是createWebHashHistory则应该去掉/&#xff0c;如果是createWebHistory则应该加上/ 页面引用,一种异步加载&#xff0c;一种同步加载&…

LeetCode 热题 100 | 二叉树(二)

目录 1 543. 二叉树的直径 2 102. 二叉树的层序遍历 3 108. 将有序数组转换为二叉搜索树 菜鸟做题&#xff0c;语言是 C 1 543. 二叉树的直径 这道题和 124. 二叉树中的最大路径和 太像了 题眼&#xff1a;二叉树的 直径 是指树中任意两个节点之间 最长路径的长度 。…

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

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

人工智能 — 特征选择、特征提取、PCA

目录 一、特征选择1、定义2、原因3、做法4、生成过程5、停止条件 二、特征提取三、PCA 算法1、零均值化&#xff08;中心化&#xff09;2、方差3、协方差4、协方差矩阵5、对协方差矩阵求特征值、特征矩阵6、对特征值进行排序7、评价模型8、代码实现9、sklearn 库10、鸢尾花实例…

【数据结构与算法(Java版)】深度剖析二分查找算法

【二分查找算法】的时间复杂度为O(log n)&#xff0c;其中n为数组的长度。因为每次查找都将查找范围缩小一半&#xff0c;所以算法的时间复杂度是对数级别的。 目录 前言 二分查找算法是什么&#xff1f; 算法实现 方式一&#xff1a;&#xff08;左闭右闭&#xff09; 文…

电机控制常见的外围器件

小型断路器&#xff1a; 这些通通都叫小型断路器&#xff0c;二十年的老电工不一定都认识&#xff0c;不信看看_哔哩哔哩_bilibili 1PIN 2PIN 3PIN 4PIN: 正常情况下火线和零线的电流是相等的&#xff0c;但是漏电的情况下&#xff0c;两线的电流差值大于30毫安&#xff0c;漏…

合纵连横 – 以 Flink 和 Amazon MSK 构建 Amazon DocumentDB 之间的实时数据同步

在大数据时代&#xff0c;实时数据同步已经有很多地方应用&#xff0c;包括从在线数据库构建实时数据仓库&#xff0c;跨区域数据复制。行业落地场景众多&#xff0c;例如&#xff0c;电商 GMV 数据实时统计&#xff0c;用户行为分析&#xff0c;广告投放效果实时追踪&#xff…

笔记本hp6930p安装Android-x86避坑日记

一、序言 农历癸卯年前大扫除&#xff0c;翻出老机hp6930p&#xff0c;闲来无事&#xff0c;便安装Android-x86玩玩&#xff0c;期间多次入坑&#xff0c;随手记之以避坑。 笔记本配置&#xff1a;T9600,4G内存&#xff0c;120G固态160G机械硬盘 二、Android-x86系统简介 官…

2023最新盲盒交友脱单系统源码

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 或 源码软件库 最新盲盒交友脱单系统源码&#xff0c;纸条广场&#xff0c;单独抽取/连抽/同城抽取/高质量盒子 新增功能包括心动推荐&#xff…

备考2024年高考全国甲卷文科数学:历年选择题真题练一练

距离2024年高考还有三个多月的时间&#xff0c;最后这个时间&#xff0c;同学们基本上是以刷题为主。刷题的时候最重要的是把往年的真题吃透&#xff0c;因为真题是严格按照考纲出的&#xff0c;掌握了真题后面的知识点&#xff0c;并能举一反三地运用&#xff0c;那么高考的高…

用Python Matplotlib画图导致paper中含有Type-3字体,如何解决?

用Python Matplotlib画图导致paper中含有Type-3字体&#xff0c;如何解决&#xff1f; 在提交ACM或者IEEE论文之前&#xff0c;都会有格式的检查&#xff0c;格式的其中一个要求是paper中不能含有Type-3的字体。因为Type-1和True Type字体都是矢量字体&#xff0c;而Type-3并不…

老杨说运维 | 运维大数据价值探索

文末附有视频 伴随第六届双态IT乌镇用户大会的圆满完成&#xff0c;擎创科技“一体化数智管理和大模型应用”主题研讨会也正式落下了帷幕。 云原生转型正成为很多行业未来发展战略&#xff0c;伴随国家对信创数字化要求的深入推进&#xff0c;面对敏稳共存这一近年出现的新难…

MySQL死锁产生的原因和解决方法

一.什么是死锁 要想知道MYSQL死锁产生的原因,就要知道什么是死锁?在了解什么是死锁之前,先来看一个概念:线程安全问题 1.线程安全问题 1.1什么是线程安全问题 线程安全问题&#xff0c;指的是在多线程环境当中&#xff0c;线程并发访问某个资源&#xff0c;从而导致的原子性&a…

RocketMQ快速实战以及集群架构原理详解

RocketMQ快速实战以及集群架构原理详解 组成部分 启动Rocket服务之前要先启动NameServer NameServer 提供轻量级Broker路由服务&#xff0c;主要是提供服务注册 Broker 实际处理消息存储、转发等服务的核心组件 Producer 消息生产者集群&#xff0c;通常为业务系统中的一个功…

板块二 JSP和JSTL:第四节 EL表达式 来自【汤米尼克的JAVAEE全套教程专栏】

板块二 JSP和JSTL&#xff1a;第四节 EL表达式 一、什么是表达式语言二、表达式取值&#xff08;1&#xff09;访问JSP四大作用域&#xff08;2&#xff09;访问List和Map&#xff08;3&#xff09;访问JavaBean 三、 EL的各种运算符&#xff08;1&#xff09;.和[ ]运算符&…

汇编语言与接口技术实践——秒表

1. 设计要求 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,实现电子秒表。 功能要求: (1)计时精度达到百分之一秒; (2)能按键记录下5次时间并通过按键回看 (3)设置时间,实现倒计时,时间到,数码管闪烁 10 次,并激发蜂鸣器,可通过按键解除。 2. 设计思…

抖音数据抓取工具|短视频下载工具|视频内容提取软件

一、开发背景&#xff1a; 随着抖音平台的流行&#xff0c;越来越多的人希望能够下载抖音视频以进行个人收藏或分享。然而&#xff0c;目前在网上找到的抖音视频下载工具功能单一&#xff0c;操作繁琐&#xff0c;无法满足用户的需求。因此&#xff0c;我们决定开发一款功能强大…

java面试题之mysql篇

1、数据库索引 ​​​​​​​ 索引是对数据库表中一列或多列的值进行排序的一种结构&#xff0c;使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她&#xff0c;则与在表中搜索所有的行相比&#xff0c;索引有助于更快地获取信息。 索引的一个主要…