20天速通LeetCodeday13:关于回溯

前言

在掌握递归思想后,理解回溯是递归的一种典型应用,核心是:做出选择-递归深入-撤销选择(回溯) 。通过题目,掌握路径记录,剪枝判断和终止条件的写法,能独立写出标准回溯模板。

理解回溯的本质:在对一颗显示的决策树做遍历,每一个分叉都是一个决策点,每一条从根到叶子的路径都是一个答案

46:全排列

题目要求:给定一个没有重复数字的数组nums

要求:返回所有可能的全排列

核心思路

回溯算法

  1. 逐步构建排列
  2. 当前选择一个数字;放入路径path
  3. 递归剩下数字-构造更长路径
  4. 回退(撤销选择)-尝试下一个数字

代码实现

java 复制代码
public List<List<Integer>> premute(int[] nums){
List<List<Integer>> res=new ArrayList<>();
boolean[] uesd=new boolean[nums.length];//标记数字是否被用过
List<Integer> path=new ArrayLsit<>();
backtrack(nums,path,used,res);
return res;
}
private void backtrack(int[] nums,List<Integer> path,boolean[] used,List<List<Integer>> res){
if(path.size()==nums.length){
res.add(new ArrayLsit<>(path));//找到一个完整排列顺序
}
for(int i=0;i<nums.length;i++){
if(used[i]) continue;//已经只用过的数字直接跳过

//选择数字
path.add(nums[i]);
used[i]=true;
//递归构建下一层排列
backtrack(nums,path,used,res);
//回退,撤销选择
path.remove(path.size()-1);
used[i]=false;
}
}

总结

作为掌握回溯算法的第一题,重点回溯的实现原理:通过for循环选择第一个作为开始的数字;将该数字放在判断是否使用过的boolean数组中;继续递归重新挑选数字,直到将第一个完整排列选出来之后,就进行回溯,从叶子节点往上直到根节点。

77:组合

题目要求:给定两个整数n和k

要求:从1-k中选出k个数字的所有组合

核心思路

回溯算法

与上一题的区别:每次递归只选择当前数字之后的数字,所以就不需要记录一个数字是否用过了,直接用path存储当前组合。

代码实现

java 复制代码
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        backtrack(n, k, 1, path, res);
        return res;
    }

    private void backtrack(int n, int k, int start, List<Integer> path, List<List<Integer>> res) {
        // 终止条件:当前组合长度 = k
        if (path.size() == k) {
            res.add(new ArrayList<>(path));  // 拷贝 path
            return;
        }

        // 从 start 开始选择数字,避免重复
        for (int i = start; i <= n; i++) {
            path.add(i);             // 选择数字
            backtrack(n, k, i + 1, path, res); // 递归
            path.remove(path.size() - 1);     // 撤销选择(回溯)
        }
    }
}

总结

与上一题进行比较,进一步了解回溯所在的精华。path记录路径,以及后续的撤销也需要path,backtrack的for循环,用来挑选数字。

78:子集

题目要求:给定一个整数数组

要求返回所有子集

核心思路

回溯算法

和上一题类似,区别在于子集长度0-n都有可能;每次递归都可以选择或不选择当前数字

代码实现

java 复制代码
public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        backtrack(nums, 0, path, res);
        return res;
    }

private void build(int[] nums,int start, List<Integer> path, List<List<Integer>> res){
//每到一个节点,当前path都是一个结果
res.add(new ArrayList<>(path));
//遍历剩余数字
for(int i=start;i<nums.length;i++){
path.add(nums[i]);
backtrack(nums,i+1,path,res);//递归
path.remove(path.size()-1);
}
}

总结

回溯的套路依然是:选择-递归-回溯

区别是path的选择:每一个path都是正确的

相关推荐
All for pursuit.33 分钟前
【回溯-7】494.目标和
数据结构·c++·算法·leetcode
白杨尚青34 分钟前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl
Jasmine_llq35 分钟前
《P17461 [GESP202609 八级] 生成树计数》
算法·栈·tarjan 算法·边双连通分量·深度优先搜索 dfs·tarjan 保存当前路径节点·模乘法
Jasmine_llq37 分钟前
《P17462 [GESP202609 八级] 末班车》
算法·dijkstra 算法·最大化版本,求最长可行值·建反向图(逆图 / 反转边)·多源 dijkstra 思想·对每个终点单独跑一遍djst·离线预处理 + 在线查询
the3clipse1 小时前
H.265熵编码核心:CABAC自适应二进制算术编码详解——如何将语法元素高效压缩为比特流
人工智能·算法·视频编码·h.265·hevc·cabac·cavlc
CQU_JIAKE1 小时前
10.4【A】
算法
Godspeed Zhao2 小时前
现代智能雷达技术19——算法(5)
算法
(Charon)2 小时前
【C++面试】RAII到底是什么:从资源管理理解C++对象生命周期
c++·算法·面试
Omics Pro2 小时前
之江实验室NAR|虚拟细胞3阶段训练范式
数据库·人工智能·算法·机器学习·自然语言处理
Tisfy2 小时前
LeetCode 0678.有效的括号字符串:O(n)+O(1)一次遍历
算法·leetcode·字符串·题解·贪心·括号匹配