深度优先搜索和回溯结合后的终极模板

Posted Python与算法社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度优先搜索和回溯结合后的终极模板相关的知识,希望对你有一定的参考价值。

1 回顾

昨天  推送了一个深度搜索和回溯结合的题目和另4道类似题,今天,逐个分析后4道题,最后提炼出模板。


2 分析4道题

1) 集合内元素都不相同,求子集,举一个例子:

 1 nums = [1,2,3], 子集为:
2 [ 
3   [3
], 
4   [1], 
5   [2],
6  [1,2,3],
7  [1,3],
8  [2,3],
9  [1,2],
10  []
11]

实现代码:

 1class Solution {
2    public List<List<Integer>> subsets(int[] nums) {
3        List<List<Integer>> list = new ArrayList<>();
4        Arrays.sort(nums);
5        dfs(listnew ArrayList<>(), nums, 0);
6        return list;
7    }
8
9    private void dfs(List<List<Integer>> list , 
10                     List<Integer> temp, 
11                     int [] nums, 
12                     int start){
13        list.add(new ArrayList<>(temp));
14        for(int i = start; i < nums.length; i++){ //depth first search
15            temp.add(nums[i]);
16            dfs(list, temp, nums, i + 1); //start位置加1,重要!!!
17            temp.remove(temp.size() - 1); //出栈时依次移除末尾元素
18        }
19    }
20}

用上面代码跑出的打印出的结果如下所示,如上代码所示,因为是深度优先搜索,把以1为根的所有子集先找出,在找出以2为根的所有子集,最后找出以3为根的所有子集。

1[[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]

短短的几行代码足以实现,可见递归的简洁性。

2) 集合内元素可能相同,求子集

 1nums = [1,2,2], 子集为:
2
3[
4  [2
],
5  [1],
6  [1,2,2],
7  [2,2],
8  [1,2],
9  []
10]

实现代码仅与上面【集合内元素都不相同,求子集】有一个差别:处理1和第一个2,1和第二个2的情况只取一种。

 1class Solution {
2    public List<List<Integer>> subsetsWithDup(int[] nums) {
3        List<List<Integer>> list = new ArrayList<>();
4        Arrays.sort(nums);
5        dfs(listnew ArrayList<>(), nums, 0);
6        return list;
7    }
8
9    private void dfs(List<List<Integer>> listList<Integer> temp, int [] nums, int start){
10        list.add(new ArrayList<>(temp));
11        for(int i = start; i < nums.length; i++){
12            if(i > start && nums[i] == nums[i-1]) //含有重复元素的子集
13                continue
14            temp.add(nums[i]);
15            dfs(list, temp, nums, i + 1);
16            temp.remove(temp.size() - 1);
17        }
18    } 
19}

打印结果的顺序如下:

1[[],[1],[1,2],[1,2,2],[2],[2,2]]

3) 求集合的不同组合序列

1[1,1,2] 的不同组合序列:
2
3[
4  [1,1,2
],
5  [1,2,1],
6  [2,1,1]
7]
在以上求子集的题目基础上,这个就比较简单了,只取与原来长度相等的序列且要回溯,代码如下:
 1class Solution {
2    public List<List<Integer>> permuteUnique(int[] nums) {
3    List<List<Integer>> list = new ArrayList<>();
4    Arrays.sort(nums);
5    dfs(listnew ArrayList<>(), nums, new boolean[nums.length]);
6    return list;
7  }
8
9    private void dfs(List<List<Integer>> listList<Integer> temp, int [] nums, boolean [] used){
10        if(temp.size() == nums.length){
11            list.add(new ArrayList<>(temp));
12        } 
13        else{
14            for(int i = 0; i < nums.length; i++){
15                if(used[i] || 
16                   i > 0 && nums[i] == nums[i-1] && !used[i - 1]) 
17                    continue
18                used[i] = true
19                temp.add(nums[i]);
20                dfs(list, temp, nums, used);
21                used[i] = false
22                temp.remove(temp.size() - 1);
23            }
24        }
25    }
26}
这个含有重复元素的全排序难点在于处理重复元素时的技巧,此处采用一个判断元素当前是否位于栈中的布尔数组。
4) 回文数那道题目,大家自己想一想用上面的模板怎么求解
3 模板
代码模板,详见文字说明
 1 class Solution {
2     public List<List<Integer>> subsetsWithDup(int[] nums) {
3         List<List<Integer>> list = new ArrayList<>();
4         Arrays.sort(nums);
5         dfs(listnew ArrayList<>(), nums, 0);
6         return list;
7     }
8
9     private void dfs(List<List<Integer>> listList<Integer> temp, int [] nums, int start){
10        /*此处判断是否拿到一个可行解*/
11        list.add(new ArrayList<>(temp));
12
13        /*深度优先搜索*/
14        for(int i = start; i < nums.length; i++){
15            /*可行解的约束条件*/
16            if(i > start && nums[i] == nums[i-1]) //含有重复元素的子集
17                continue
18            /*找到解的一部分元素,作为根元素*/
19            temp.add(nums[i]);
20            /*添加枝叶*/
21            dfs(list, temp, nums, i + 1);
22            /*枝叶出栈时需要的操作,必有的是退出枝叶*/
23            temp.remove(temp.size() - 1);
24        }
25    } 
26}


学知识,送红包系列活动


预知是否获得红包,请参考获奖名单。



Python与机器学习算法频道


欢迎点赞和转发

以上是关于深度优先搜索和回溯结合后的终极模板的主要内容,如果未能解决你的问题,请参考以下文章

深度优先搜索算法基础模板

广度优先和深度优先算法

回溯法与深度优先搜索

信息学赛培 | 08 不可不知的搜索与回溯——深度优先搜索算法与实例详解

如何在深度优先搜索算法中正确回溯?

回溯 DFS 深度优先搜索[待更新]