当前位置: 首页 > news >正文

【Java数据结构】——动态规划,分治,回溯

目录

一.动态规划

1.不同路径走法(力扣62)

2.旅行商问题

3.01背包问题

4.完全背包问题(每个物品都可以一直装)

1.完全背包

2.钢条切割

3.整数拆分问题(343)

5.最长公共子串

6.最长公共子序列

2.两个字符串的删除

3.最长递增子序列

二.分治

1.快速幂

2.平方根的整数部分

3.至少有k个字符的最长子串 

三.回溯

1.全排列(以及全排列不重复)

2.组合(力扣77)

3.组合之和

1.力扣39 每个数字都可以多次使用。

2.力扣40(每个数字不能重复,且不能包含重复的组合)

3.力扣216(凑目标值)


一.动态规划

1.不同路径走法(力扣62)

    public int uniquePaths2(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];}

2.旅行商问题

3.01背包问题

    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];}static int select2(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] = item0.value;} else {                 // 装不下dp[0][j] = 0;}}print(dp);for (int i = 1; i < dp.length; i++) {Item item = items[i];for (int j = 0; j < total + 1; j++) {int x = dp[i - 1][j];if (j >= item.weight) {dp[i][j] = Integer.max(x,
//                            上次剩余空间能装的最大价值 + 当前物品价值dp[i - 1][j - item.weight] + item.value);} else {dp[i][j] = x;}}print(dp);}return dp[dp.length - 1][total];}

优化为一维数组时,要从右往左处理(与完全背包问题的不同)

    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];}

4.完全背包问题(每个物品都可以一直装)

1.完全背包

    private static int select3(Item[] items, int total) {//情况1:第一行int[] dp = new int[total + 1];for(Item item : items){for (int j = 0; j < total + 1; j++) {if (j >= item.weight){//装得下dp[j] = Math.max(item.value + dp[j - item.weight], dp[j]);}}}System.out.println("dp = " + Arrays.toString(dp));return dp[total];}

2.钢条切割

   /*  if(放得下)dp[i][j]=max(dp[i-1][j],当前物品价值+dp[i][j-物品重量]else(放不下)dp[i][j]=dp[i-1][j]0   1   2   3   4       钢条总长度=背包容量1       1   11  111 1111(1) (2) (3) (4)2       1   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++) {for (int j = 1; j < n + 1; j++) {if (j >= i) { // 放得下dp[i][j] = Integer.max(dp[i - 1][j], values[i] + dp[i][j - i]);} else { // 放不下dp[i][j] = dp[i - 1][j];}}print(dp);}return dp[values.length - 1][n];}

3.整数拆分问题(343)

    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];}

5.最长公共子串

    static int lcs1(String a, String b) {int[][] dp = new int[b.length()][a.length()];char[] array = a.toCharArray();char[] brray = b.toCharArray();int max = 0;for (int i = 0; i < b.length(); i++) {for (int j = 0; j < a.length(); j++) {if (brray[i] == array[j]){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;}

6.最长公共子序列

    public int longestCommonSubsequence1(String text1, String text2) {char[] a = text1.toCharArray();char[] b = text2.toCharArray();int[][] dp = new int[a.length + 1][b.length + 1];for (int i = 1; i < a.length + 1; i++) {for (int j = 1; j < b.length + 1; j++) {if (a[i-1] == b[j-1]){dp[i][j] = dp[i-1][j-1] + 1;}else {dp[i][j] = Integer.max(dp[i-1][j], dp[i][j-1]);}}}return dp[a.length][b.length];}

2.两个字符串的删除

    public int minDistance1(String text1, String text2) {char[] a = text1.toCharArray();char[] b = text2.toCharArray();int[][] dp = new int[a.length + 1][b.length + 1];for (int i = 1; i < a.length + 1; i++) {for (int j = 1; j < b.length + 1; j++) {if (a[i-1] == b[j-1]){dp[i][j] = dp[i-1][j-1] + 1;}else {dp[i][j] = Integer.max(dp[i-1][j], dp[i][j-1]);}}}return a.length + b.length - 2 * dp[a.length][b.length];}
}

3.最长递增子序列

    /*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();}

二.分治

1.快速幂

    static double myPow1(double x, int n) {int p = n;if (p < 0){p = -p;}double v = myPowPositive1(x, p);return n < 0 ? 1/v : v;}static double myPowPositive1(double x, long n) {if (n == 0){return 1.0;}if (n == 1){return x;}double y = myPowPositive1(x, n / 2);if ((n & 1) == 0){return y * y;}else {return x * y * y;}}

2.平方根的整数部分

    static int mySqrt1(int x) {int i = 1;int j = x;int r = 0;while (i <= j) {int m = (i + j) >>> 1;int mm = m * m;if (mm == x){return m;} else if (mm > x) {j = m - 1;}else {i = m + 1;r = m;}}return r;}

3.至少有k个字符的最长子串 

你截一个子串,里面的重复出现的字母必须大于k,并求出最长子串的长度。

    static int longestSubstring1(String s, int k) {int[] nums = new int[26];//遍历字符串,把出现次数存到数组中for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);int count = nums[c - 'a']++;}//遍历数组找出次数少于k的元素,从那个位置断开char[] chars = s.toCharArray();for (int i = 0; i < chars.length; i++) {char c = chars[i];int count = nums[c - 'a'];if (count < k && count != 0) {int j = i + 1;while(j < s.length() && nums[chars[j] - 'a'] < k) {j++;}System.out.println(s.substring(0,i) + "\t" + s.substring(j));return Integer.max(longestSubstring(s.substring(0, i), k),longestSubstring(s.substring(j), k));}}return s.length();}

三.回溯

1.全排列(以及全排列不重复)

    static List<List<Integer>> permute(int[] nums) {List<List<Integer>> result = new ArrayList<>();Arrays.sort(nums);dfs(nums, new boolean[nums.length], new LinkedList<>(), result);return result;}static void dfs(int[] nums, boolean[] visited, LinkedList<Integer> stack, List<List<Integer>> result) {if (stack.size() == nums.length) {
//            System.out.println(stack);result.add(new ArrayList<>(stack));return;}// 遍历 nums 数组,发现没有被使用的数字,则将其标记为使用,并加入 stackfor (int i = 0; i < nums.length; i++) {if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]){continue;}if (!visited[i]) {stack.push(nums[i]);visited[i] = true;dfs(nums, visited, stack, result);visited[i] = false;stack.pop();}}}

2.组合(力扣77)

n:1-n的数字,k:从中选k个进行组合

    // 此 n 代表数字范围, 1~nstatic List<List<Integer>> combine(int n, int k) {List<List<Integer>> result = new ArrayList<>();dfs1(1, n, k, new LinkedList<>(), result);return result;}// start 起始处理数字static void dfs(int start, int n, int k,LinkedList<Integer> stack,List<List<Integer>> result) {if (stack.size() == k) {result.add(new ArrayList<>(stack));return;}for (int i = start; i <= n ; i++) {//剪枝//  还差几个数字          剩余可用数字if (k - stack.size() > n - i + 1) {continue;}stack.push(i);dfs(i + 1, n, k, stack, result);stack.pop();}}

问题:为什么全排列需要固定,组合却不用?

因为全排列如1,1,3和3,1,1是不同的排列,而在组合中则是一种,所以不需要固定。

3.组合之和

1.力扣39 每个数字都可以多次使用。

    static void dfs1(int start, int[] candidates, int target, LinkedList<Integer> stack, List<List<Integer>> result) {if (target == 0){result.add(new ArrayList<>(stack));return;}for (int i = start; i < candidates.length; i++) {int candidate = candidates[i];if (target < candidate){continue;}stack.push(candidate);dfs1(i, candidates, target - candidate, stack, result);stack.pop();}}

2.力扣40(每个数字不能重复,且不能包含重复的组合)

还是之前那个visited固定的思想。

    static void dfs1(int start, int[] candidates, boolean[] visited, int target, LinkedList<Integer> stack, List<List<Integer>> result) {if (target == 0){result.add(new ArrayList<>(stack));return;}for (int i = start; i < candidates.length; i++) {int candidate = candidates[i];if (target < candidate){continue;}if (i > 0 && candidates[i] == candidates[i - 1] && !visited[i - 1]){continue;}stack.push(candidate);visited[i] = true;dfs1(i + 1, candidates, visited, target - candidate, stack, result);visited[i] = false;stack.pop();}}

3.力扣216(凑目标值)

    static void dfs1(int start, int target, int k, LinkedList<Integer> stack, List<List<Integer>> result) {if (target == 0 && stack.size() == k){result.add(new ArrayList<>(stack));return;}for (int i = start; i <= 9; i++) {//剪枝if (target < i){continue;}if (stack.size() == k) {continue;}stack.push(i);dfs1(i + 1, target - i, k, stack, result);stack.pop();}}

http://www.dtcms.com/a/395990.html

相关文章:

  • 【开题答辩全过程】以 基于Springboot的个性化运动管理平台为例,包含答辩的问题和答案
  • 静默安装 Oracle Database 21c on CentOS 7.6
  • 【数值分析】07-非线性方程的求根方法-基本概念、二分法求根
  • Golang常用Web开发库
  • Sub-GHz射频芯片,如何降低IoT终端功耗,提升传输性能?
  • 敏捷管理核心:价值驱动与快速响应的底层逻辑
  • 使用pip命令离线安装python库
  • Kubernetes 控制器深度解析:DaemonSet
  • 38.应用层协议HTTP(一)
  • VMware虚拟机ubuntu20.04共享文件夹无法使用
  • PyTorch 神经网络工具箱核心知识点总结
  • 豆包Seedream 4.0:全面测评、玩法探索与Prompt解读
  • STM32_02_GPIO
  • Flink SlotSharingGroup 机制详解
  • Final Cut Pro X fcpx音视频剪辑编辑(Mac中文)
  • 【LeetCode_88】合并两个有序数组
  • PromptPilot 发布:AI 提示词工程化新利器,首月零元体验
  • MySQL-详解数据库中的触发器
  • JVM调优实战及常量池详解
  • 字典树(Trie)
  • AI浏览器概述:Browser Use、Computer Use、Fellou
  • 「docker」三、3分钟快速安装docker
  • Altium Designer(AD)自定义PCB形状
  • 基于ZYNQ的创世SD NAND卡读写TXT文本实验
  • 文心快码入选2025人工智能AI4SE“银弹”标杆案例
  • 什么是SDN(Software Defined Netwok)
  • GitLab-如何基于现有项目仓库,复制出新的项目仓库
  • 本科大二第三周学习周报
  • 三、自定义Button模板触发器(纯XAML)
  • tar 将多个文件或目录打包成一个单独的归档文件