【算法】【回溯】两道经典排列问题OJ详解【力扣46 力扣47】【超详细的回溯算法教程】让我们牢牢把握回溯的精髓

作者: @小小Programmer
这是我的主页:@小小Programmer
在食用这篇博客之前,博主在这里介绍一下其它高质量的编程学习栏目:
数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏:算法 这里可以说是博主的刷题历程,里面总结了一些经典的力扣上的题目,和算法实现的总结,对考试和竞赛都是很有帮助的!
力扣刷题专栏Leetcode想要冲击ACM、蓝桥杯或者大学生程序设计竞赛的伙伴,这里面都是博主的刷题记录,希望对你们有帮助!

先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力。看完之后别忘记关注我哦!️️️

本篇建议收藏后食用~

题目:

OJ4646. 全排列
OJ4747. 全排列 II

OJ46 全排列

题目描述

实现思路

首先,这两道题我们肯定是要用回溯实现的,我们要通过回溯,来找到每一种排列方式。
因此,在这里,博主先带着大家复习一下回溯算法的精髓

回溯算法的三部曲:

  1. 确定递归函数参数和返回值
  2. 确定递归终止条件
  3. 确定单层递归逻辑

一:确定递归函数的参数和返回值
这里和组合问题是不一样的,因为排列问题是有顺序可言的,比如例题一:我们要找[1,2,3]的排列,第二次从2开始找的时候,前面的1也是要进去的,即[1,2..][2,1...]是不同的排列,因此,我们的递归函数除了原来的数组之外,还需要一个数组来记录,哪一个数字已经用过了。 比如第一个数字挑了2,即[2,...],此时,第二个数字的选择只能是1或者3,因为2已经用过了。
所以我们的递归函数:

void backtracking(vector<int>& nums, vector<bool>& used)

当然,我们还需要创建全局的两个数组,一个用来做最后结果的收集,一个用于递归回溯。

vector<vector<int>>ret;
vector<int>path;

二:确定递归终止条件
很明显,当递归数组(path)满了的时候,就终止递归。
比如:求[1,2,3]的排列,当一个数组path[]收集到3个数的时候,就要返回了,比如path里面是[2,1,3]的时候,如果只有两个或者一个数,递归就要继续。

        if (path.size() == nums.size()) {
ret.push_back(path);
return;
}

三. 确定单层递归逻辑
当然,单层搜索就是递归了

  • 递归回溯永不分离
  • 一次递归伴随着一次回溯

所以我们每次递归完一定要记得撤销,回溯。

完整代码

//OJ46 全排列
class Solution {
private:
vector<vector<int>>ret;
vector<int>path;
void backtracking(vector<int>& nums, vector<bool>& used) {
//此时说明找到了一组结果
//2.终止条件
if (path.size() == nums.size()) {
ret.push_back(path);
return;
}
//3.单层搜索
for (int i = 0; i < nums.size(); i++) {//每次都要从头开始搜索
if (used[i] == true)continue;//如果这个数字用过了,直接跳过本次循环
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
//撤销,回溯
path.pop_back();
used[i] = false;
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<bool>used(nums.size(), false);
backtracking(nums, used);
return ret;
}
}; /*
* 和组合问题的区别
* 每层都是从0开始搜索,而不是从startIndex开始搜索---[1,2]中用过1了,但是[2,1]中还得用1
* 需要used数组记录path中都存放了哪些元素
*/
//used是用来防止同一个数选两次的

OJ47 全排列ll

题目描述

实现思路

这其实就是一个经典的去重问题,方法同样是用used数组来完成去重

要注意的点:

  • 去重之前要对数组进行排序,要将一样的数字放在一起
  • 去重的判断条件,当当前下标所对应的数和前一个下标所对应的数一致,并且这个数并不是在同一个树枝上时去重

一:确定递归函数的返回值和参数

void backtracking(vector<int>& nums, vector<bool>& used)

二:确定递归的终止条件,这些都和前面一样的。

        if (path.size() == nums.size()) {
ret.push_back(path);
return;
}

三:确定单层搜索逻辑:

  • 具体的去重实现,请看完整代码的注释,若还有不明白的,可以私信博主噢! 其实这个去重思路是非常经典的思路,是必须要掌握的!

完整代码

class Solution {
private:
vector<vector<int>>ret;
vector<int>path;
void backtracking(vector<int>& nums, vector<bool>& used) {
if (path.size() == nums.size()) {
ret.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)continue;//首先一定要i>0,保证这不是这棵树的根节点
//nums[i]==nums[i-1]说明可能会出现重复,但是此时不确定是这两个相同的数出现在同一树层上还是同一树枝上
//如果实在同一树枝上,是可以的,比如在[1,1,2]是没问题的
//但是如果是在同一树层上是不行的,可能会出现重复
//所以used[i-1]=false 保证这是在同一树层上的,而不是同一树枝上的
if (used[i] == false) {
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<bool>used(nums.size(), false);
backtracking(nums, used);
return ret;
}
};
//为什么去重的时候写第二个&&左边写
//used[i-1]==false;或used[i-1]=true;都可以呢?
//因为在树枝上去重和在树层上去重都可以的
//在树层上去重的效率很高,
//在树枝上去也可以,但是做了很多无用的搜索

尾声

看到这里相信你对排列问题的这两道OJ已经有一定的理解了,其实排列问题是一个非常经典的我们必须要掌握的问题。
在走之前,可以再看看博主的这些专栏内容对你是否有帮助: 有的话请不要吝啬你们的点赞收藏关注和转发噢!

数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏:算法 这里可以说是博主的刷题历程,里面总结了一些经典的力扣上的题目,和算法实现的总结,对考试和竞赛都是很有帮助的!
力扣刷题专栏Leetcode想要冲击ACM、蓝桥杯或者大学生程序设计竞赛的伙伴,这里面都是博主的刷题记录,希望对你们有帮助!

【算法】【回溯】两道经典排列问题OJ详解【力扣46 力扣47】【超详细的回溯算法教程】让我们牢牢把握回溯的精髓的更多相关文章

  1. 【转载】NeurIPS 2018 | 腾讯AI Lab详解3大热点:模型压缩、机器学习及最优化算法

    原文:NeurIPS 2018 | 腾讯AI Lab详解3大热点:模型压缩.机器学习及最优化算法 导读 AI领域顶会NeurIPS正在加拿大蒙特利尔举办.本文针对实验室关注的几个研究热点,模型压缩.自 ...

  2. PHP用strtotime()函数比较两个时间的大小实例详解

    在PHP开发中,我们经常会对两个时间的大小进行判断,但是,在PHP中,两个时间是不可以直接进行比较,因为时间是由年.月.日.时.分.秒组成的,所以,如果需要将两个时间进行比较的话,我们首先要做的就是将 ...

  3. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  4. 【转】小波与小波包、小波包分解与信号重构、小波包能量特征提取 暨 小波包分解后实现按频率大小分布重新排列(Matlab 程序详解)

    转:https://blog.csdn.net/cqfdcw/article/details/84995904 小波与小波包.小波包分解与信号重构.小波包能量特征提取   (Matlab 程序详解) ...

  5. openerp经典收藏 字段定义详解(转载)

    字段定义详解 原文地址:http://shine-it.net/index.php/topic,2159.0.htmlhttp://blog.sina.com.cn/s/blog_57ded94e01 ...

  6. openerp经典收藏 对象定义详解(转载)

    对象定义详解 原文地址:http://shine-it.net/index.php/topic,2159.0.htmlhttp://blog.sina.com.cn/s/blog_57ded94e01 ...

  7. 一个经典的 HTTP协议详解

    1引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1 ...

  8. 二分算法题目训练(三)——Anton and Making Potions详解

    codeforces734C——Anton and Making Potions详解 Anton and Making Potions 题目描述(google翻译) 安东正在玩一个非常有趣的电脑游戏, ...

  9. [转]从两道经典试题谈C/C++中联合体(union)的使用

    宋宝华 21cnbao sweek@21cn.com 试题一:编写一段程序判断系统中的CPU是Little endian还是Big endian模式? 分析: 作为一个计算机相关专业的人,我们应该在计 ...

  10. 看到两道小学数学题,实在是解不动,用js写了一下

    把一个自然数的约数(除去它本身)按照从小到大的顺序写在它的左边,可以得到一个多位数,比如6的约数是1,2,3,写成一个多位数是1236,假如这个多位数中,没有直复数字,那么我们你这个多位数是唯一的.请 ...

随机推荐

  1. StringBuilder 线程不安全,到底哪里不安全?

    StringBuilder 线程不安全,到底哪里不安全? 在Java中,字符串拼接是一个非常常见的操作,而对于频繁变动的字符串内容,使用StringBuilder是一个性能优化的选择.但是,Strin ...

  2. 双非本科拿下oppo sp!这位粉丝太强了!

    哈喽,大家好,我是仲一.今天分享的是一位双非本科生拿下oppo sp的秋招经验.当时,这位粉丝咨询我offer选择的时候,看到年薪31W这个数字,我以为他是研究生.后来,再三确认了,他确实是本科生. ...

  3. vant下拉加载更多,上拉刷新

    https://www.bilibili.com/video/BV1zq4y1p7ga?p=218 List 组件通过 loading 和 finished 两个变量控制加载状态,当组件滚动到底部时, ...

  4. eyebeam高级设置

    概述 VOIP测试过程中,经常会用到各种各样的SIP终端,eyebeam是其中最常见的一种. 在eyebeam的配置option中,只有少量的配置选项,有些特殊的设置无法配置. 比如DTMF码的发码形 ...

  5. C#实现斐波拉切数列求和

    C#实现斐波拉切数列求和 private void button1_Click(object sender, EventArgs e) { listBox1.Items.Clear();//清空Lis ...

  6. Apache ShardingSphere 实现分库分表及读写分离

    本文为博主原创,未经允许不得转载: 项目demo 源码地址:https://gitee.com/xiangbaxiang/apache-shardingjdbc 1. 创建Maven项目,并配置 po ...

  7. [转帖]【oracle】oracle查询表存储大小和表空间大小

    目录 查看表分配的物理空间大小 查看表实际存储空间大小 查看每个表空间的大小 查看表空间大小及使用率 查看数据库中数据文件信息 查看临时表空间信息 oracle表大小有两种含义,即表分配的空间大小和实 ...

  8. [转帖]Oracle性能优化-大内存页配置

    一.为什么需要大页面? 如果您有一个大的RAM和SGA,那么HugePages对于Linux上更快的Oracle数据库性能是至关重要的.如果您的组合数据库SGAs很大(比如超过8GB,甚至对于更小的数 ...

  9. [转帖]深入理解mysql-第六章 mysql存储引擎InnoDB的索引-B+树索引

    一.引入索引 在没有索引的情况下,不论是根据主键列或者其他列的值进行查找,由于我们并不能快速的定位到记录所在的页,所以只能从第一个页沿着双向链表一直往下找,因为要遍历所有的数据页,时间复杂度就是O(n ...

  10. [转帖]jmeter之foreach循环控制器-03篇

    上篇我们通过正则表达式获取到了一组数据,那么怎么来用呢?下面就用foreach控制器来使用结果,如下图所示 然后再foreach控制器里添加要循环的请求,我们模拟百度搜索,value填入${id} 然 ...