LeetCode(8)-回溯:组合排列问题

leetcode-hot100-10回溯 (处理第 index 位数字),遍历当前数字对应字母→选字母→递归下一位→回溯,最终收集所有完整组合。和上题差不多,形式上会更复杂,因为是字符串,需要额外处理。) = “试探 + 撤销”,深度优先搜索 + 回退,尝试一条路,如果不通,就“退回去”试别的路。(i+1)避免重复子集,且每一步递归的路径都是一个有效子集(需即时收集)。给出数字到字母的映射如下(与电话按键相同)。如果至少一个数字的被选数量不同,则两种组合是不同的。的字符串,返回所有它能表示的字母组合。返回该数组所有可能的子集(幂集)。 阅读详情

今天来总结下LeetCode上关于回溯的应用之排列组合相关的问题 - ( ゜- ゜)つロ

1.1 LeetCode 46.全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

一般的排列组合问题的本质都是枚举,对于枚举来说,最适合的算法就是回溯算法,我画了副图来理解这个过程:

在这里插入图片描述
白色框框即为可以取值的数组,红色的数字是取出的数字,而黄色框框则为最后的结果;可以看到这是一个典型的树型结构解,而递归适合解对称类型的树型结构问题,例如二叉树问题,所以采用特殊的递归手段:回溯来解决这个问题:

private List<List<Integer>> res = new ArrayList<>();
    private boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        used = new boolean[nums.length];
        backTraceSearch(nums, 0, new LinkedList<Integer>());
        return res;
    }

    /**
     * @auther: Arong
     * @description: 回溯搜索
     * @param: [nums:含有所有元素的数组, count:当前结果中已有的元素个数, oneRes:存储当前结果]
     * @return: void
     */
    private void backTraceSearch(int[] nums, int count, LinkedList<Integer> oneRes) {
        //回溯终止条件
        if (count == nums.length) {
            res.add(new ArrayList<Integer>(oneRes));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            //当前结果中没有被使用到的元素才可取出
            if (!used[i]) {
                //已使用当前元素,标识为true,在下一次回溯搜索中不要使用该元素
                used[i] = true;
                //将当前结果添加到oneRes中,count + 1
                oneRes.addLast(nums[i]);
                //回溯搜索
                backTraceSearch(nums, count + 1, oneRes);
                //将状态变回原来的状况
                oneRes.removeLast();
                used[i] = false;
            }
        }
        return;
    }

1.2 LeetCode 47. 全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这个问题和46题是一样的思路,但是不能像之前那样全部枚举出来,因为数组中存在重复的元素,这时就需要用到剪枝优化技术:即在回溯搜索的过程中,剪去完全不可能成立的情况(路径),优化从而避免多余的搜索。
如下图,我们应该让红色方块在同一个层次中只存在一个,就能避免接下来多余的重复搜索了,那么如何进行剪枝呢?

从图中我们可以清晰地看到,当同一层次的节点取的值和上一个节点是一样的,譬如第二层的第一个节点取了1,第二个节点也取了1时,之后的搜索都是重复的,这就是剪枝的条件:nums[i] != nums[i - 1];

在这里插入图片描述

	private List<List<Integer>> res = new ArrayList<>();
    private boolean[] used = null;

    public List<List<Integer>> permuteUnique(int[] nums) {
        if (nums.length == 0) return res;
        used = new boolean[nums.length];
        //先对nums进行排序
        Arrays.sort(nums);
        serachWithPruning(nums, 0, new LinkedList<Integer>());
        return res;
    }

    /**
     * @auther: Arong
     * @description:  带有剪枝优化的回溯搜索
     * @param: [nums:含有所有元素的数组, count:当前结果中已有的元素个数, oneRes:存储当前结果]
     * @return: void
     */
    private void serachWithPruning(int[] nums, int count, LinkedList<Integer> oneRes) {
        //回溯终止条件
        if (count == nums.length) {
            res.add(new ArrayList<Integer>(oneRes));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
             //剪枝优化,nums[i - 1] == nums[i](i >= 1时 && !used[i - 1]表示的是上一节点取值和当前取值相同)
             if (i >= 1 && nums[i - 1] == nums[i] && !used[i - 1]) {
                    continue;
             }
            
             if (!used[i]) {
                used[i] = true;
                oneRes.addLast(nums[i]);
                //回溯搜索
                serachWithPruning(nums, count + 1, oneRes);
                //状态转变回来
                oneRes.removeLast();
                used[i] = false;
            }
        }
        return;
    }

1.3 LeetCode 77. 组合

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combinations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

组合问题和排列问题不同的地方在于,用过的元素就不再使用,在方法参数中多传递一个start开始索引即可,每次将其+1

private List<List<Integer>> res = new ArrayList<>();
    private boolean[] used;

    public List<List<Integer>> combine(int n, int k) {
        if (n <= 0) return res;
        used = new boolean[n];
        backTraceSearch(n, k, 1, new LinkedList<Integer>());
        return res;
    }

    private void backTraceSearch(int n, int k, int start, LinkedList<Integer> oneRes) {
        //回溯终止条件
        if (oneRes.size() == k) {
            res.add(new ArrayList<Integer>(oneRes));
            return;
        }
        for (int i = start; i <= n; i++) {
            oneRes.offerLast(i);
            //回溯搜索
            backTraceSearch(n, k, i + 1, oneRes);
            //把状态变回来
            oneRes.removeLast();
        }
        return;
    }

未完持续…

回溯问题详解 回溯问题 一、基本概念 回溯算法实际上是一个枚举的过程,在搜索尝试过程中寻找问题的解,发现不满足求解回溯返回。 基本思想: 在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。 1、若用回溯法求问题的所有解时,要回溯到根,且... 阅读详情

相关推荐

基于Windows环境的OGG远程抽取异常(经典模式)OGG-02830 Formatting error

MOS提供的解决方法,根据MOS的提示是由于使用的OGG版本太新了,经典模式下已经弃用了这种远程抽取方式。问题:Windows环境下启用远程抽取ADG备库的数据,在启动抽取进程的时候出现如下错误提示。

Mrzhou的博客 380

Python递归实现枚举排列(给定一个元素不重复的列表,返回这些元素所有的排列形式)

一、问题描述 如果我们有一个列表[1,2,3],我们很清楚地知道,这里面元素的所有排列如下: [1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,1,2] [3,2,1] 因为问题规模比较小,手动写出结果不难。我们可以回顾一下枚举的思路,其实主要就是两点: 每个元素都要做排头兵 除了排头兵以外,剩下的元素也要穷尽所有的排列 基于这样的思路,我们很容易想到用递归...

weixin_44520259的博客 2114

风二西CTF流量题大集合-刷题笔记|基础题(1)

部分题目已包含脚本和解题视频,但更建议自行分析和手搓脚本。

zerorzeror的博客 2766

全排列

题目:给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] 分析:利用树形结构 枚举出所有可行解集合,然后利用剪枝方法 得到符合某一约束规则的可行解。 利用回溯法实现。 回溯法的基本思想是先递归,然后回溯, 当回溯到树形结构中的某一节点时,代码是如何记住每一步索引的呢? 个人理解是因为递归是利用栈分配空间的,所以每一次回...

识物专栏 322

YOLOv8缺陷检测可视化界面实战:PyQt5布局设计与代码实现

本文详细介绍了如何利用PyQt5为YOLOv8缺陷检测模型构建一个专业、易用的可视化界面。通过实战讲解PyQt5的布局管理器设计、信号槽机制与YOLOv8核心的集成,帮助开发者快速将AI模型部署为直观的桌面应用,提升工业质检等场景的落地效率。

redis7keeper的博客 758

解放双手:用KUKA示教器白键一键触发复杂工艺,自定义你的快捷指令

本文详细介绍了如何利用KUKA示教器的工艺白键功能,通过自定义快捷指令一键触发复杂工艺,显著提升自动化产线效率。文章涵盖UserTech技术栈解析、KRL脚本封装、人机交互视觉工程及工业实战策略,帮助工程师实现机械臂操作的高阶优化。

weixin_30379531的博客 433

LeetCode 刷题 [C++] 第46题.全排列(回溯法+深度优先遍历DFS)

使用回溯法+深度优先遍历DFS解决全排列问题

心之所向、力之所及 971

骑砍Ⅱ霸主MOD开发(16)-FaceKey&BannerKey

摘要:本文介绍了FaceKey人物模型和BannerKey旗帜模型的生成流程。FaceKey通过序列化参数生成人物模型,包括头部(脸部、嘴、睫毛、眼睛)、眉毛、头发、身体和躯干等组件,每个部分通过特定标签和骨骼绑定实现。BannerKey则通过解析参数生成旗帜模型,包括模型、贴图和颜色等元素。两种模型都采用参数化设计和XML配置文件实现模型生成与定制。

骑砍战团&霸主MOD开发 2289

【LeetCode】46.全排列①

题目描述 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 解题思路 思路① 该题给的输入数组是没有重复项的,故该题采用递归DFS来解决,我们需要用到一个visited数组标记某个数是否访问过,然后DFS递归函数的的...

刘猿猿 1107

微信小程序 - 真机调试请求异常 Provisional headers are shown,微信小程序开发者工具调试没问题就真机测试时出现请求报错(微信小程序请求接口提示Provisional h)

微信小程序开发 Request Headers: Provisional headers are shown,微信开发工具请求正常,真机调试和上线之后出现 Provisional headers are shown,微信小程序开发工具调试没问题,真机调试Provisional headers are shown,在开发工具调试,请求正常没问题,使用真机调试,请求异常,微信小程序真机调试时后台是本地服务器,显示“Provisional headers are shown”问题解决,微信小程序websocket

🏆 前端领域优质创作者 1万+

Matlab 曲面平滑与点云处理

曲面平滑是一种常见的数学和计算机图形学技术,可以用来消除噪声、填补数据间隙,以及改善曲面的外观。在点云处理中,曲面平滑也被广泛应用于重建、拟合和可视化等领域。本文将介绍如何使用 Matlab 进行曲面平滑和点云处理,并提供相应的源代码。通过以上步骤,我们可以使用 Matlab 进行曲面平滑和点云处理。你可以根据具体需求调整参数和算法,以获得理想的曲面平滑效果。接下来,我们可以使用平滑算法对三角化的网格进行曲面平滑。以上代码将绘制原始点云和重建后的点云,并在图形中显示坐标轴和图例。表示平滑的迭代次数。

QfcaLinux的博客 753

leetcode_46.全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 解析:本题采用回溯法,在每一次尝试时,将被选择的数字放置在数组的前列,保证在之后的步骤中不会再次选中已经被选中过一次的数字。 class Solution { public: vect...

qq_37292201的博客 257

倾斜摄影与地面激光点云融合高精度建模研究

本文研究了倾斜摄影与地面激光点云融合精细化建模技术,并通过相应的源代码实现了建模过程。该方法将倾斜摄影和激光扫描相结合,能够获得高精度的三维建模结果,为相关领域的研究和应用提供了有力支持。近年来,倾斜摄影和激光扫描技术的快速发展为高精度三维建模提供了新的机遇和挑战。本文针对倾斜摄影与地面激光点云融合建模这一前沿领域展开研究,旨在通过相应的源代码实现精细化的建模过程。同时,使用激光扫描仪进行地面激光扫描,获取地面的点云数据。经过数据融合和精细化建模处理后,我们获得了高精度的三维建模结果。

LpmShell的博客 1248

【力扣hot100】回溯专题|全排列、子集、字母组合、组合总和、括号生成、单词搜索、分割回文串、N皇后

这篇文章摘要了回溯算法的核心思想及其在三个经典问题中的应用:全排列、子集和电话号码字母组合。每个问题通过递归和回溯的三步流程(当前操作、子问题、下一个子问题)解决,并通过代码示例展示了具体实现。全排列通过检查数字是否已使用来剪枝,子集通过选择或不选当前元素构建决策树,电话号码问题则使用固定长度数组优化路径记录。这些案例体现了回溯算法在组合问题中的通用性和效率。

2401_87144364的博客 634

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

力扣hot100—系列8-回溯算法

画树形图:回溯问题一定要在纸上画出递归树。死记模板:先模仿->recursion->path.pop这个固定套路。区分去重:搞清楚什么时候需要startIndex(组合/子集问题),什么时候需要used数组(排列问题)。调试:如果逻辑乱了,在入口打印path,能直观看到程序是怎么“跳”的。

qq_60957452的博客 782

贝叶斯统计 [韦来生编]

贝叶斯(Bayes)统计是近几十年来迅速发展起来的数理统计的一个重要分支。贝叶斯方法与经典统计方法的主要不同之处是进行统计推断时除了利用样本信息外,还要利用参数的先验信息,因此可以提高统计推断或统计决策的效果。它在经济、金融、生物、医学、自然科学和社会科学等许多领域具有广泛的应用。贝叶斯方法的研究已渗透到了统计学的几乎所有领域。作者在给中国科学技术大学概率论与数理统计专业本科生开设的“数理统计”课程中有一章专门讲授“贝叶斯方法和统计决策理论”,近十年来也给中国科学技术大学概率统计专业研究生开设过几次“贝叶斯分析”课。本书是在对过去讲稿的内容作了适当的增减和调整的基础上完成的。  本书共分六章。第1章是绪论,介绍了贝叶斯统计的若干基本概念,同时对必要的数理统计的基础知识有重点地作了回顾。第二章介绍了确定先验分布的若干可供选择的方法。第三章介绍了几类常见统计模型参数的后验分布的主要结果和计算方法。第四章和第五章分别介绍了“贝叶斯统计推断”和“贝叶斯统计决策”的内容。第六章介绍了贝叶斯统计计算的若干方法,包括蒙特卡洛方法和马尔可夫链蒙特卡洛(MCMC)方法以及相关统计软件的简介。本书的每一章附右大量的例题和习题,书末附有常用的几个表格和部分习题解答供读者查用。  大约可在54学时内讲授本书的第1章至第六章的主要内容,教师可根据学时需要选讲本书第1章至第六章的部分内容。书中标“*”号的章节可略去不讲,留给读者作为阅读材料。第六章例题中的R代码和部分例题的数据文件等可从作者个人主页下载。  作者在编写本书的过程中参考了J.O.Berger教授的《统计决策论及贝叶斯分析》和茆诗松教授编写的《贝叶斯统计》等书中的一些内容,以及《贝叶斯分析》一书中由张伟平博士编写的有关贝叶斯统计计算的一些内容。在此表示衷心感谢。  本书编写准备过程中,中国科学技术大学统计与金融系的几个研究生帮助完成了本书部分中文的录入和排版,作者对他们的辛勤工作表示真诚的感谢。高等教育出版社为本书的出版给予了大力支持。在此一并致谢。

Leetcode回溯算法part1

回溯算法本质是一种👉 只要你写了递归,只要你在递归返回前“撤销状态”,那你就在用回溯。

Ll1304525298的博客 1183

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

leetcode-hot100-回溯

回溯

XSYaaaaan的博客 335

回溯算法:一个模板解决排列组合问题

以n = 4, k = 2为例,如下图所示,从上往下看,在第一层的时候,可以选择1,2,3,4,假设第一个选定为1(将选定的元素存入path中,即path=[1]),那么第二层的元素只能选择2,3,4(要保证不相等,不能重复),当第二层的元素选择2,即path=[1,2]时,第二个元素选定后,此时path的长度等于k的长度,一个排列结果就计算出来了,加入到结果result中去,接着回溯,按照同样的逻辑运行下去,最后所有组合结果。有的同学会问,既然回溯法并不是高效的算法,为什么还要用它?

a779868946的博客 954

回溯算法之组合和排列结果如何去重

回溯算法中有两个难点:一是剪枝,二是去重。剪枝是指在回溯搜索过程中,根据一定的条件判断,提前终止某些不可能产生最优解或有效解的搜索分支,从而减少搜索量,提高算法效率。去重指在回溯算法生成所有可能解的过程中,去除重复的解,确保最终结果集中的每个解都是唯一的。排序 + 标记先对输入的数组进行排序,这样相同的元素会相邻。在回溯过程中,使用一个标记数组来记录每个元素是否已经被使用过。当遇到相同元素时,如果该元素的前一个相同元素没有被使用过,那么当前元素就不能使用,否则会产生重复组合。

云泽野の编程日记 1476

(二)LeetCode系列题型 | 全排列和组合问题

LeetCode系列题型 | 组合问题

Skies_的博客 2043

leetCode 46. 全排列 + 回溯算法 + 图解 + 笔记

1.leetCode 77.组合问题 、leetCode 131.切割问题、leetCode 78.子集问题需要用startIndex,组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列_哔哩哔哩_bilibili。是用来标记取过了哪些元素,那接下来,在剩余的这个集合里边取的时候,取过的元素别重复取就行了!是相同的组合,因为元素相同。是不同的排序组合,因为排序不同;给定一个不含重复数字的数组。,处理排列问题就不用使用。3).单层搜索的逻辑。2).递归的终止条件。

呵呵哒!的博客 1658

【leetcode】回溯法:组合、排列

目录 77. 组合 46. 全排列 47. 全排列 II 39. 组合总和 40. 组合总和 II 216. 组合总和 III 78. 子集 90. 子集 II 77. 组合 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 这道题是比较简单的回溯法题目,这一题的解答模板就是回溯问题的基本模...

Mr_health的博客 538

经典的回溯算法题leetcode组合问题整理及思路代码详解

倘若各位不太清楚回溯算法可以去看我上一篇文章。

xiaoliii0401的博客 1829

leetcode回溯算法系列(排列组合篇)

LeetCode回溯算法系列(排列组合篇)

weixin_72076848的博客 523

LeetCode 267. 回文排列 II(回溯)

文章目录1. 题目2. 解题 1. 题目 给定一个字符串 s ,返回其通过重新排列组合后所有可能的回文字符串,并去除重复的组合。 如不能形成任何回文排列时,则返回一个空列表。 示例 1: 输入: "aabb" 输出: ["abba", "baab"] 示例 2: 输入: "abc" 输出: [] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/palindrome-permutation-ii 著作权归领扣网络所有。商业转载请联系官方授权,非商业

Michael是个半路程序员 2868

LeetCode 40. 组合总和 II(排列组合 回溯)

1. 题目 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 说明: 所有数字(包括目标数)都是正整数。 解集不能包含重复的组合。 示例 1: 输入: candidates = [10,1,2,7,6,1,5], target = 8, 所求解集为...

Michael是个半路程序员 1291
上一篇: 数据结构(10)-TrieTree(字典树)的实现
下一篇: 数据结构(11)-UnionFind(并查集)的实现与优化
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值