首页 > 其他分享 >14-回溯

14-回溯

时间:2023-11-09 09:12:27浏览次数:29  
标签:index 14 temp nums int dfs 回溯 new

14. 回溯

问自己三个问题:

  1. 当前操作应该是什么?
  2. 子问题是什么?
  3. 下一个子问题应该是什么?

14.1 Master公式

形如
$$
T(N) = a * T(\frac{N}{b}) + O(N^d)
$$

其中的a、b、d都是常数的递归函数,可以直接通过Master公式来确定时间复杂度

如果 log(b,a) < d,复杂度为O(N^d)

如果 log(b,a) > d,复杂度为O(N^log(b,a))

如果 log(b,a) == d,复杂度为O(N^d * logN)

14.1 子集型回溯

子集型回溯本质上就是看对于每一个元素,都可以选/不选。

14.1.1 所有子集

1. 题目

https://leetcode-cn.com/problems/subsets/

给定一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

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

示例 2:

输入:nums = [0]
输出:[[],[0]]

2. 思路

方法1 :从输入的角度考虑

​ 对于[1,2]这个集合,站在输入的角度,每个数可以在子集中,也可以不在。

问自己:

  1. 当前操作:枚举第i个数,选/不选
  2. 子问题:从下表≥i的数字中构造子集
  3. 下一个子问题:从下表≥i+1的数字中构造子集

方法2:从答案的角度考虑

​ 对于[1,2]这个集合,每次枚举第一个选谁,第二个选谁......

​ 每个节点都是答案,但是[1,2]和[2,1]是同一个答案,要去重复

问自己:

  1. 当前操作:枚举下标 j ≥ i的数字,加入答案
  2. 子问题:从下表 ≥ i的数字中构造子集
  3. 下一个子问题?从下标 ≥ j + 1的数字中构造子集

image-20230729160849482

3. 代码

输入角度考虑:

class Solution {
    List<Integer> temp;
    List<List<Integer>> ans;
    public List<List<Integer>> subsets(int[] nums) {
        temp = new ArrayList<>();
        ans = new ArrayList<>();
        dfs(nums,0);
        return ans;
    }

    public void dfs(int[] nums, int depth){
        int len = nums.length;
        if(depth == len){
            // 新建一个拷贝数组
            ans.add(new ArrayList<Integer>(temp));
            return;
        }

        // 不选
        dfs(nums,depth+1);
        
        // 选择
        temp.add(nums[depth]);
        dfs(nums,depth+1);
        // 删除就删除最后一个,remove(index) - 是index不是值
        temp.remove(temp.size()-1);
    }
}

从答案考虑:

class Solution {
    List<Integer> temp;
    List<List<Integer>> ans;
    public List<List<Integer>> subsets(int[] nums) {
        temp = new ArrayList<>();
        ans = new ArrayList<>();
        dfs(nums,0);
        return ans;
    }
    // 从答案的角度:每次选择不回退,每个都是答案
    public void dfs(int[] nums, int index){
        ans.add(new ArrayList<>(temp));
        int len = nums.length;
        for(int i = index; i < len; i++){
            temp.add(nums[i]);
            dfs(nums,i+1);
            temp.remove(temp.size()-1);
        }
        
    }
}

14.2 组合型回溯

14.2.1 含有k个元素的组合

1. 题目

https://leetcode-cn.com/problems/combinations/

给定两个整数 nk,返回 1 ... n 中所有可能的 k 个数的组合。

示例 1:

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

示例 2:

输入: n = 1, k = 1
输出: [[1]]

2. 思路

跟之前的子集型回溯,从答案思考相似,但是增加一点判断条件即可。

image-20230729173929342

注意:如果当前位置i+k后已经大于了n,也就是后面无解,不用遍历了。

为了保证无重复,只允许一个方向的遍历(比如[3,2,1],遍历了2不允许回到3)。

2. 代码

class Solution {
    List<List<Integer>> res;
    List<Integer> temp;
    public List<List<Integer>> combine(int n, int k) {
        res = new ArrayList<>();
        temp = new ArrayList<>();
        dfs(1,k,n);
        return res;
    }
    public void dfs(int index, int k, int n){
        if(temp.size() == k) {
            res.add(new ArrayList<Integer>(temp));
            return;
        }
        // 剩下的数如果小于k个了,返回
        // 剩下的数为:1 2 3 4 5 比如n=5,index = 3,此时剩下234三个数
        // 剩下的数 < k - 已经选了的数
        // 倒叙更简单,可以看灵神的倒叙
        if(n - index + 1 < k - temp.size()) return;
        // 加index后的所有,如果加过了某一个i,就不能再加前面的了
        for(int i = index; i <= n; i++){
            temp.add(i);
            dfs(i+1,k,n);
            temp.remove(temp.size()-1);
        }
    }
}

14.3 排列型回溯

14.3.1 没有重复元素集合的全排列

1. 题目

https://leetcode-cn.com/problems/permutations/

给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。

示例 1:

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

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

2. 思路

问问自己:

  1. 当前操作:从s中枚举要填入的数字
  2. 子问题:构造排列≥i的部分,剩余部分未选的集合为s
  3. 下一个子问题:构造排列 ≥ i+1的部分,剩余未选集合为s-

3. 代码

class Solution {
    List<List<Integer>> res;
    List<Integer> temp;
    public List<List<Integer>> permute(int[] nums) {
        res = new ArrayList<>();
        temp = new ArrayList<>();
        int[] isVisit = new int[nums.length];
        dfs(0,isVisit,nums);

        return res;
    }
    // 第i个位置需要填数,已经被选过的位置,数组nums
    public void dfs(int index,int[] isVisit, int[]nums){
        // dfs一定会选中一个,这样就不需要判断index之前有没有没被选中的情况
        if(index == nums.length){
            res.add(new ArrayList<>(temp));
            return;
        }
        
        for(int i = 0; i < nums.length; i++){
            if(isVisit[i] == 1) continue;
            isVisit[i] = 1;
            temp.add(nums[i]);
            dfs(index+1,isVisit,nums);
            temp.remove(temp.size()-1);
            isVisit[i] = 0;
        }
    }
}

标签:index,14,temp,nums,int,dfs,回溯,new
From: https://www.cnblogs.com/ylw-blogs/p/17818896.html

相关文章

  • AGC014E
    居然自己想出了AGCE。首先考虑删边再加红边的本质是什么。容易发现,如果一条目标树上的边当前还没有被加上,且这条边所连两点在原树上的路径被切断,则此时一定无解。因为不管怎么加删边,这都是一棵树,而此时两点路径上一定有红边。所以,我们就可以得到此时可以新增一条边\((u,v)\)......
  • P2146 [NOI2015] 软件包管理器 题解
    [NOI2015]软件包管理器题目背景Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debi......
  • 【洛谷 P4414】[COCI2006-2007#2] ABC 题解(排序)
    [COCI2006-2007#2]ABC题面翻译【题目描述】三个整数分别为。这三个数字不会按照这样的顺序给你,但它们始终满足条件:。为了看起来更加简洁明了,我们希望你可以按照给定的顺序重新排列它们。【输入格式】第一行包含三个正整数,不一定是按这个顺序。这三个数字都小于或等于。第二行包......
  • 回溯随笔
    回溯问题通用模板voidbacktracking(参数){if(终止条件){存放结果;return;}for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){处理节点;backtracking(路径,选择列表);//递归回溯,撤销处理结果}......
  • cf1446C. Xor Tree
    https://codeforces.com/problemset/problem/1446/C断断续续想了挺久的,还发现看错题了。首先一个显然的结论是不会成环,证明显然。突破口在于从高位往低位考虑,我们按照最高一位的值分成两类,一类是这一位为0,另一类为1,那么显然在我们不进行任何操作的时候,如果两个集合都不为空,那么......
  • Microsoft Visual C++ 14.0 is required.
    问题:配置detectron2的时候报错,MicrosoftVisualC++14.0isrequired.解决:按照上面的网址去下载MicrosoftC++BulidTools这个工具,安装对应的包即可 ......
  • NodeJS系列(14)- TypeScript (一) | 安装 TypeScript、TypeScript 常用类型
    JavaScript现在是有史以来最广泛使用的跨平台语言之一。JavaScript最初是一种用于向网页添加微不足道的交互性的小型脚本语言,现已发展成为各种规模的前端和后端应用的首选语言。虽然用JavaScript编写的程序的大小、作用域和复杂性呈指数级增长,但JavaScript语言表达不同代码......
  • Oracle ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务
    oracle10g配置客户端时,测试连接出现错误(NetConfigurationAssistant--本地Net服务名配置):ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务随后打开:D:\oracle\product\10.2.0\db_1\NETWORK\ADMIN\listener.ora 内容如下:#listener.oraNetworkConfigurationFile:D......
  • Day14
    黑夜给了我黑色的眼睛,我却用他来寻找光明。单词承载历史,历史成就单词梦魇Incubus(lieon)Succubus(lieunder)cubliedown横躺cubincubusincubateincubationincubativeincubatorcubicleconcubineconcubinagecumbsuccumbincumbentrecumbentrecumbencyp......
  • CF1486F
    都3202年了,我还是永远喜欢正向计数(bushi)。显然是CF1336F弱化版。值得一提的是,在standing上有一个老哥,交了一份很神奇的代码,好像拼了CF1336F的std,然后拼了两份,一减就求得答案。考虑分类计数,目前我们有两条链\(x\toy\)和\(p\toq\)。记录\(l_{x,y}\)为两条链底......