回溯算法的模板

模板

 1 /**
 2  * 回溯算法的模板
 3  * @param 路径:已走过的路径,已经选择到的数据
 4  * @param 选择列表:原始的数据列表,一般是如此int[] nums
 5  */
 6 List<List<Integer>> res = new ArrayList<>();
 7 public void trackBack(路径, 选择列表) {
 8     if () {
 9       res.add(new ArrayList<>(路径));
10     return;
11   }
12   
13   // start每层(从0开始,或者,递增加1);end的值可以做剪枝,如组合问题,不够选了直接退出:i < n-(k-tack.size()) + 1
14   for (待选择的值 : 选择列表) {
15       if (排查非法的值) {
16         continue;
17     }
18       选择;
19     trackBack(路径, 选择列表);
20     撤销选择,回溯;
21   }
22 }

 

 

leetcode真题示例:

39. 组合总和

如果要不能重复,模板中不使用for,该使用【选择/不选择】的两个分支。详见:

 1 /**
 2  * 39. 组合总和
 3  * https://leetcode-cn.com/problems/combination-sum/
 4  */
 5 public class Problem39 {
 6 
 7     public static void main(String[] args) {
 8         int[] candidates = new int[]{2,3,6,7};
 9         int target = 7;
10         Solution39 solution39 = new Solution39();
11         System.out.println(solution39.combinationSum(candidates, target));
12     }
13 }
14 
15 class Solution39 {
16     private List<List<Integer>> res = new ArrayList<>();
17     public List<List<Integer>> combinationSum(int[] candidates, int target) {
18         trackBack(candidates, target, 0, new ArrayList<>());
19         return res;
20     }
21 
22     private void trackBack(int[] candidates, int target, int idx, List<Integer> track) {
23         if (target < 0 || idx == candidates.length) {
24             return;
25         }
26         if (target == 0) {
27             res.add(new ArrayList<>(track));
28             return;
29         }
30         // 不选择当前值的分支
31         trackBack(candidates, target, idx + 1, track);
32 
33         // 选择当前值的分支
34         int current = candidates[idx];
35         // 根据条件剪枝
36         if (target - current >= 0) {
37             track.add(current);
38               // 值可以重复使用,所以idx不增加,下次选择继续使用
39             trackBack(candidates, target - current, idx, track);
40             track.remove(track.size() - 1);
41         }
42     }
43 }

 

40. 组合总和 II

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 /**
 8  * 40. 组合总和 II
 9  * https://leetcode-cn.com/problems/combination-sum-ii/
10  */
11 public class Problem40 {
12     public static void main(String[] args) {
13 
14     }
15 }
16 
17 class Solution40 {
18     private List<List<Integer>> res = new ArrayList<>();
19     private boolean[] vis;
20     public List<List<Integer>> combinationSum2(int[] candidates, int target) {
21         vis = new boolean[candidates.length];
22         // 处理重复的值,要先进行排序
23         Arrays.sort(candidates);
24         trackBack(candidates, target, 0, new ArrayList<>());
25         return res;
26     }
27 
28     private void trackBack(int[] candidates, int target, int idx, List<Integer> track) {
29         if (target == 0) {
30             res.add(new ArrayList<>(track));
31             return;
32         }
33         if (target < 0 || idx == candidates.length) {
34             return;
35         }
36 
37         for (int i = idx; i < candidates.length; i ++) {
38             int current = candidates[i];
39             // 1、已经被使用了,跳过。2、当前值与前一个值相同,如果前一个值没被选择,跳过
40             if (vis[i] || (i > 0 && current == candidates[i - 1] && !vis[i - 1])) {
41                 continue;
42             }
43             // 根据条件剪枝
44             if (target - current >= 0) {
45                 vis[i] = true;
46                 track.add(current);
47                 // 值可以重复使用,所以idx不增加,下次选择继续使用
48                 trackBack(candidates, target - current, i + 1, track);
49                 track.remove(track.size() - 1);
50                 vis[i] = false;
51             }
52         }
53     }
54 }

 

216. 组合总和 III

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * 216. 组合总和 III
 8  * https://leetcode-cn.com/problems/combination-sum-iii/
 9  */
10 public class Problem216 {
11     public static void main(String[] args) {
12 
13     }
14 }
15 
16 class Solution216 {
17     public List<List<Integer>> combinationSum3(int k, int n) {
18         List<List<Integer>> res = new ArrayList<>();
19         trackBack(k, n, 1, new ArrayList<>(), res);
20         return res;
21     }
22 
23     private void trackBack(int k, int n, int start, List<Integer> track, List<List<Integer>> res) {
24         int min = 1; int max = 9;
25         if (n == 0 && k == track.size()) {
26             res.add(new ArrayList<>(track));
27             return;
28         }
29         if (n < 0 || start > max) {
30             return;
31         }
32 
33         for (int i = start; i <= max; i++) {
34             if (n - i >= 0) {
35                 track.add(i);
36                 trackBack(k, n - i, i + 1, track, res);
37                 track.remove(track.size() - 1);
38             }
39         }
40     }
41 }

 

78. 子集

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * 78. 子集
 8  * https://leetcode-cn.com/problems/subsets/
 9  */
10 public class Problem78 {
11     public static void main(String[] args) {
12         int[] nums = new int[]{1,2,3};
13         Solution78 solution78 = new Solution78();
14         System.out.println(solution78.subsets(nums));
15     }
16 }
17 
18 class Solution78 {
19     private List<List<Integer>> res = new ArrayList<>();
20     public List<List<Integer>> subsets(int[] nums) {
21         r(nums, 0, new ArrayList<>());
22         return res;
23     }
24 
25     private void r(int[] nums, int start, List<Integer> p) {
26         int length = nums.length;
27         if (start >= length) {
28             res.add(new ArrayList<>(p));
29             return;
30         }
31 
32         // 选当前节点
33         p.add(nums[start]);
34         r(nums, start+1, p);
35         p.remove(p.size() - 1);
36 
37         // 不选当前节点
38         r(nums, start + 1, p);
39     }
40 }

 

90. 子集 II

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 
 7 /**
 8  * 90. 子集 II
 9  * https://leetcode-cn.com/problems/subsets-ii/
10  */
11 public class Problem90 {
12     public static void main(String[] args) {
13 
14     }
15 }
16 
17 class Solution {
18     private boolean[] vis;
19     public List<List<Integer>> subsetsWithDup(int[] nums) {
20         List<List<Integer>> res = new ArrayList<>();
21         vis = new boolean[nums.length];
22         // 解决有重复的问题,先排序
23         Arrays.sort(nums);
24 
25         trackBack(nums, 0, new ArrayList<>(), res);
26         return res;
27     }
28 
29     private void trackBack(int[] nums, int start, List<Integer> track, List<List<Integer>> res) {
30         res.add(new ArrayList<>(track));
31         int length = nums.length;
32         if (start >= length) {
33             return;
34         }
35 
36         for (int i = start; i < length; i++) {
37             // 相同的元素,同一递归层级,只选择第一个元素
38             if (vis[i] || (i >0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
39                 continue;
40             }
41             vis[i] = true;
42             track.add(nums[i]);
43             trackBack(nums, i + 1, track, res);
44             track.remove(track.size() - 1);
45             vis[i] = false;
46         }
47     }
48 }

 

401. 二进制手表

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 /**
 7  * 401. 二进制手表
 8  * https://leetcode-cn.com/problems/binary-watch/
 9  */
10 public class Problem401 {
11     public static void main(String[] args) {
12         int turnedOn = 5;
13         Solution401 solution401 = new Solution401();
14         System.out.println(solution401.readBinaryWatch(turnedOn));
15     }
16 }
17 
18 class Solution401 {
19     public List<String> readBinaryWatch(int turnedOn) {
20         List<String> res = new ArrayList<>();
21         trackBack(turnedOn, new StringBuilder(), res);
22         return res;
23     }
24 
25     private void trackBack(int turnedOn, StringBuilder track, List<String> res) {
26         int remain = 10 - track.length();
27         // 剩余的点不够选了,直接退出
28         if (turnedOn > remain) {
29             return;
30         }
31         if (turnedOn == 0) {
32             // 用个新的对象来补充0
33             StringBuilder newSb = new StringBuilder(track);
34             for (int i = 0; i <remain; i++) {
35                 newSb.append("0");
36             }
37             int upInt = getInt(newSb, 0, 4);
38             int downInt = getInt(newSb, 4, 10);
39             if (upInt <= 11 && downInt <= 59) {
40                 res.add(trans(upInt, false) + ":" + trans(downInt, true));
41             }
42             return;
43         }
44 
45         // 选当前点
46         track.append("1");
47         trackBack(turnedOn - 1, track, res);
48         track = track.deleteCharAt(track.length() - 1);
49         // 不选当前点
50         track.append("0");
51         trackBack(turnedOn, track, res);
52         track = track.deleteCharAt(track.length() - 1);
53     }
54 
55     /**
56      * 格式化两位数字,根据flag判断是否补齐0
57      * @param i 数字
58      * @param flag 是否补0
59      * @return 格式化化的数字
60      */
61     private String trans(int i, boolean flag) {
62         if (flag) {
63             return String.format("%02d", i);
64         } else {
65             return String.format("%d", i);
66         }
67     }
68 
69     /**
70      * 从字符串中解析出数字
71      * @param track 原字符
72      * @param start 开始位置
73      * @param end 结束位置
74      * @return 数字
75      */
76     private int getInt(StringBuilder track, int start, int end) {
77         String s = track.substring(start, end).toString();
78         return Integer.parseInt(s, 2);
79     }
80 }

 

79. 单词搜索

 1 package com.example.demo.leetcode;
 2 
 3 import java.util.Objects;
 4 
 5 /**
 6  * 79. 单词搜索
 7  * https://leetcode-cn.com/problems/word-search/
 8  */
 9 public class Problem79 {
10     public static void main(String[] args) {
11         char[][] board = new char[][] {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}};
12         String word = "ABCB";
13         Solution79 solution79 = new Solution79();
14         System.out.println(solution79.exist(board, word));
15     }
16 }
17 
18 class Solution79 {
19     private int m;
20     private int n;
21     private final int[][] directions = new int[][]{{-1, 0},{1, 0},{0, -1},{0, 1}};
22 
23     private boolean[][] vis;
24 
25     public boolean exist(char[][] board, String word) {
26         m = board.length;
27         n = board[0].length;
28         vis = new boolean[m][n];
29         for (int x = 0; x < m; x++) {
30             for (int y = 0; y < n; y++) {
31 //                System.out.println("最外 >>>>>>>>>> " + x + " " + y);
32                 if (trackBack(board, word, 0, x, y)) {
33                     return true;
34                 }
35             }
36         }
37 
38         return false;
39     }
40 
41     private boolean trackBack(char[][] board, String word, int index, int x, int y) {
42 //        System.out.println(" >>>>>>>>>> 每次递归 >>>>>>>>>> " + x + " " + y);
43         if (index == word.length() - 1) {
44 //            System.out.println("----- 最终找到啦");
45             return board[x][y] == word.charAt(index);
46         }
47 
48         if (Objects.equals(board[x][y], word.charAt(index))) {
49 //            System.out.println(" >>>>>>>>>> 当前值找到啦,");
50             vis[x][y] = true;
51             for (int i = 0; i < 4; i++) {
52 //                System.out.println("i = " + i);
53                 int newX = x + directions[i][0];
54                 int newY = y + directions[i][1];
55                 if (checkArea(newX, newY) && !vis[newX][newY]) {
56                     if (trackBack(board, word, index + 1, newX, newY)) {
57                         return true;
58                     }
59                 }
60             }
61             vis[x][y] = false;
62         }
63 
64         return false;
65     }
66 
67     private boolean checkArea(int x, int y) {
68         return x >= 0 && x < m && y >= 0 && y < n;
69     }
70 }

 

200. 岛屿数量

 1 package com.example.demo.leetcode;
 2 
 3 /**
 4  * 200. 岛屿数量
 5  * https://leetcode-cn.com/problems/number-of-islands/
 6  */
 7 public class Problem200 {
 8     public static void main(String[] args) {
 9 //        char[][] grid = new char[][] {
10 //                {'1','1','1','1','0'},
11 //                {'1','1','0','1','0'},
12 //                {'1','1','0','0','0'},
13 //                {'0','0','0','0','0'}
14 //        };
15 
16         char[][] grid = new char[][] {
17                 {'1','1','0','0','0'},
18                 {'1','1','0','0','0'},
19                 {'0','0','1','0','0'},
20                 {'0','0','0','1','1'}
21         };
22 
23         Solution200 solution200 = new Solution200();
24         System.out.println(solution200.numIslands(grid));
25     }
26 }
27 
28 class Solution200 {
29     private int m;
30     private int n;
31     private boolean[][] vis;
32     // 此处上下左右顺序无关。如果有顺序要求的话,需要注意数组内容的顺序。
33     private int[][] d = new int[][]{{-1, 0},{1, 0},{0, -1},{0, 1}};
34     public int numIslands(char[][] grid) {
35         m = grid.length;
36         n = grid[0].length;
37         vis = new boolean[m][n];
38 
39         int res = 0;
40         for (int x = 0; x < m; x++) {
41             for (int y = 0; y < n; y++) {
42 //                System.out.println("最外层 >>>>>> " + x + " " + y);
43                 if (!vis[x][y] && grid[x][y] == '1') {
44 //                    System.out.println("最外层 >>>>>> 找到一个陆地" + x + " " + y);
45                     res ++;
46                     dfs(grid, x, y);
47                 }
48             }
49         }
50         return res;
51     }
52 
53     private void dfs(char[][] grid, int x, int y) {
54 //        System.out.println("递归 >>>>>> " + x + " " + y);
55         // 保证是岛屿1的,才允许进入递归
56         vis[x][y] = true;
57         for (int i = 0; i < 4; i++) {
58             int newX = x + d[i][0];
59             int newY = y + d[i][1];
60             // 保证是岛屿1的,才允许进入递归
61             if (checkArea(newX, newY) && !vis[newX][newY] && grid[newX][newY] == '1') {
62                 dfs(grid, newX, newY);
63             }
64         }
65     }
66 
67     private boolean checkArea(int x, int y) {
68         return x >= 0 && x < m && y >= 0 && y < n;
69     }
70 }

 

 

 

具体例子,请参考labuladong的详细总结:https://mp.weixin.qq.com/s/qT6WgR6Qwn7ayZkI3AineA

posted @ 2021-11-27 11:54  Z武器  阅读(203)  评论(0)    收藏  举报