栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

细说递归+回溯:通过构造可能结果的树来求解算法问题(Leetcode77.组合、Leetcode78.子集)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

细说递归+回溯:通过构造可能结果的树来求解算法问题(Leetcode77.组合、Leetcode78.子集)

我们经常会遇到如下问题:给定一列数组或数,然后举例出所有可能的组合结果,这种问题我们直观的想法可能是:逐个遍历元素,求所有可能结果,这样当所给数量级较大时,可能会爆炸;此时我们通常的解法是将所有可能结果构造成一棵树,树中每一层都是一种可能的结果。(例如下图举例构造的树)

这篇文章,我们使用Java来实现递归+回溯构造树,在构造树之前我们需要定义数据结构来存储所有可能的元素,我经常会采用的是双向队列Deque<>和列表List>,其中Deque通常用来存储当前某条路径满足条件的解,而List用来存储所有可能的解。
定义代码如下:

		//用来满足条件的结果
        List> list = new ArrayList<>();
        //定义双向队列
        Deque que = new ArrayDeque<>();

而我们通常采用向Deque队尾当中加元素实现递归,删除元素实现回溯;
递归、回溯代码如下:(通常在一个for循环体当中)

			que.addLast(i);
			//递归
            dfs(n,k,i+1,que,list);
            //回溯
            que.removeLast();

有了以上的简单概述,可能对此类问题还没有较深的印象,那么接下来举例两道通过构造递归树来求解的问题:

题1:Leetcode77.组合

题目概述:
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

算法思路:
我们可以一次遍历,比如说第一个数取1、取2…取n的时候,然后在第一个数取1情况下第二个数取2、第一个数取2情况下第二个数取3…(这里为了实现所有递归的可能不重复,我们在for循环初始值设置的时候往往是前一个数+1,这样就能避免重复);通过这种方法构造递归树,然后当Deque当中元素个数等于k的时候(递归边界)结束递归,然后进行回溯(向树的上一层退一格然后再往没有走过的枝杈遍历),递归所有可能的结果。

算法实现(Java版):

class Solution {
    public List> combine(int n, int k) {
        
        //用来满足条件的结果
        List> list = new ArrayList<>();
        //定义双向队列
        Deque que = new ArrayDeque<>();
        dfs(n,k,1,que,list);
        return list;

    }
    public void dfs(int n,int k,int begin,Deque que,List> list){
        if(que.size()==k){
            //达到递归条件
            list.add(new ArrayList<>(que));
            return;
        }
        for(int i=begin;i<=n;i++){
        	//这里从begin开始就是为了避免重复元素
            que.addLast(i);
            //递归
            dfs(n,k,i+1,que,list);
            //回溯寻找下一种可能
            que.removeLast();
        }
    }
}

题2:Leetcode78.子集

题目概述:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

算法思路:
这题,我们通过读题一看,同样也是列举所有可能的结果,这样的问题常常通过构造递归树来实现;和上一题不同的是,这题的结果长度可能为0、1…nums.length;那么我们只要通过设置递归结束的条件为Deque的长度等于子集中元素的个数即可。
ps:
在这里我们一定要注意,在for循环中实现递归的时候,for循环的结束条件是为了找到所有可能的解,这里必须将nums数组全部遍历到。

算法实现:

class Solution {
    public List> subsets(int[] nums) {
        List> list = new ArrayList<>();
        Deque que = new ArrayDeque<>();
        //实现子集的求解
        for(int i=0;i<=nums.length;i++){
            dfs(nums,i,0,que,list);
        }
        return list;
    }
    public void dfs(int[] nums,int len,int begin,Deque que,List> list){
        if(que.size()==len){
            list.add(new ArrayList<>(que));
            return;
        }
        //将所有可能的解都遍历到
        for(int i=begin;i
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777408.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号