全排列

力扣题目链接

给定一个不含重复数字的数组 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]]

思路

咋一看好像还可以用之前的套路

只要判断一下当前遍历值是否有使用过,有就跳过即可

但是这个“跳过”的操作如果还是使用beginIndex的话就会出错

一种经典的错误思路是:仍然使用beginIndex作为遍历时的起始值,当每次调用递归时就使用 当前位置+1 作为下次遍历的beginIndex

这样做的话最后只能得到一条路径上的结果,因为我们没办法即根据beginIndex去回溯又将beginIndex作为for循环的依据(递归可以回溯,for循环过了的东西是回不去的)

因此这里需要用used数组来记录当前遍历值是否出现过,如果出现过就直接跳过

此处的used仅用于记录当前值是否被选择过,其作用类似于哈希表

停止条件也不太一样,因为我们又是需要找出所有的结果,所以实际上这里还是不需要停止条件的,不过我们需要在path数组保存到足够大小的排列值时将其保存至res结果数组

代码

代码比较套路就直接贴了

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
void backtracking(vector<int>& nums, vector<bool>& used){
//确定终止条件,无
if(path.size() == nums.size()){//当path保存到足够的元素时,将其存至res
res.push_back(path);
return;
} //确定单层处理逻辑
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 res;
}
};

注意,本题使用used数组的原因是排列结果中不能重复使用某一数字

例如第一次在[1,2,3]中选了1,此时path数组为[1]

在下一层递归中仍然从[1,2,3]中选数,但是就不能再选1了

面试题 08.07. 无重复字符串的排列组合

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

示例1:

输入:S = "qwe"

输出:["qwe", "qew", "wqe", "weq", "ewq", "eqw"]

示例2:

输入:S = "ab"

输出:["ab", "ba"]

提示:

字符都是英文字母。

字符串长度在[1, 9]之间。

思路

就是全排列

代码

tips:字符串也是数组,可以使用push_back()

class Solution {
private:
vector<string> res;
string path = "";//别忘了字符串也是数组
void traversal(string& S, vector<bool>& used){
if(path.size() == S.size()){
res.push_back(path);
return;
}
for(int i = 0; i < S.size(); ++i){
if(used[i] == true) continue;
used[i] = true;
path.push_back(S[i]);
traversal(S, used);
path.pop_back();
used[i] = false;
}
}
public:
vector<string> permutation(string S) {
vector<bool> used(S.size(), false);
traversal(S, used);
return res;
}
};

剑指 Offer 38. 字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

示例:

输入:s = "abc"

输出:["abc","acb","bac","bca","cab","cba"]

限制:

1 <= s 的长度 <= 8

思路

与全排列I一模一样

代码

tips:

1、字符串可以直接作为数组使用

2、在使用s[i] == s[i - 1] && used[i - 1] == 0跳过重复值之后,不要忘记判断当前字符是否已经被使用过

这是为了避免生成重复的排列。

class Solution {
private:
vector<string> res;
string path;
void traversal(string s, vector<bool> used){
if(path.size() == s.size()){
res.push_back(path);
return;
} for(int i = 0; i < s.size(); ++i){ if(i > 0 && s[i] == s[i - 1] && used[i - 1] == 0) continue;
if (used[i] == 0) {
used[i] = true;
path.push_back(s[i]);
traversal(s, used);
used[i] = false;
path.pop_back();
}
}
}
public:
vector<string> permutation(string s) {
vector<bool> used(s.size(), false);
sort(s.begin(), s.end());
traversal(s, used);
return res;
}
};

全排列II

力扣题目链接

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

示例 1:

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

输出:

[[1,1,2],

[1,2,1],

[2,1,1]]

示例 2:

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

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

思路

与第一题不同之处是题目给的nums中多了重复值

将例1的结果画出示例图如下:

因此还需要在同层中去重,参考之前的去重操作即可(子集组合总和II

这里也需要在使用nums之前进行排序

代码分析

还是按规矩来写一遍

1、确定回溯函数的参数与返回值

跟上一题一样,不需要beginIndex,只需要used数组进行记录即可

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数与返回值
void backtracking(vector<int>& nums, vector<bool>& used){ }
public:
vector<vector<int>> permuteUnique(vector<int>& nums) { }
};

2、确定终止条件

还是跟上一题一样

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数与返回值
void backtracking(vector<int>& nums, vector<bool>& used){
//确定终止条件,无
if(path.size() == nums.size()){//当path保存到足够的元素时,将其存至res
res.push_back(path);//此时说明找到了一组
return;
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) { }
};

3、确定单层处理逻辑

在这里需要处理重复值

注意,我们需要处理的重复情况有两种

1、相邻重复值(这个很熟了,见过蛮多次的)

2、单纯的nums里出现多次的值,例如:[1,2,8,2,4],这个2就属于此类重复值

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数与返回值
void backtracking(vector<int>& nums, vector<bool>& used){
//确定终止条件,无
if(path.size() == nums.size()){//当path保存到足够的元素时,将其存至res
res.push_back(path);//此时说明找到了一组
return;
}
//确定单层处理逻辑
for(int i = 0; i < nums.size(); ++i){
if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0){
continue;//当前元素重复,跳过
}
used[i] = 1;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = 0;
} }
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
//先对nums进行排序
sort(nums.begin(), nums.end());
vector<bool> use(nums.size(), false);
backtracking(nums, used);
return res;
}
};

完整代码

在主函数中,需要对使用的nums数组先进行排序

class Solution {
private:
vector<vector<int>> res;
vector<int> path;
//确定回溯函数的参数与返回值
void backtracking(vector<int>& nums, vector<bool>& used){
//确定终止条件,无
if(path.size() == nums.size()){//当path保存到足够的元素时,将其存至res
res.push_back(path);//此时说明找到了一组
return;
}
//确定单层处理逻辑
for(int i = 0; i < nums.size(); ++i){
// used[i - 1] == true,说明同一树枝nums[i - 1]使用过
// used[i - 1] == false,说明同一树层nums[i - 1]使用过
// 如果同一树层nums[i - 1]使用过则直接跳过
if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == 0){
//找出相邻重复值
continue;//当前元素重复,跳过
}
//判断当前元素(非相邻重复值)是否被使用过
if(used[i] == true) continue;
used[i] = 1;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = 0;
} }
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
//先对nums进行排序
sort(nums.begin(), nums.end());
vector<bool> used(nums.size(), false);
backtracking(nums, used);
return res;
}
};

同样的题还有:面试题 08.08. 有重复字符串的排列组合

【LeetCode回溯算法#09】全排列,排列问题以及其中涉及的去重操作的更多相关文章

  1. 【LeetCode回溯算法#07】子集问题I+II,巩固解题模板并详解回溯算法中的去重问题

    子集 力扣题目链接 给你一个整数数组 nums ,数组中的元素 互不相同 .返回该数组所有可能的子集(幂集). 解集 不能 包含重复的子集.你可以按 任意顺序 返回解集. 示例 1: 输入:nums ...

  2. 【LeetCode回溯算法#extra01】集合划分问题【火柴拼正方形、划分k个相等子集、公平发饼干】

    火柴拼正方形 https://leetcode.cn/problems/matchsticks-to-square/ 你将得到一个整数数组 matchsticks ,其中 matchsticks[i] ...

  3. leetcode回溯算法--基础难度

    都是直接dfs,算是巩固一下 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 思路 一直 ...

  4. 【LeetCode回溯算法#06】复原IP地址详解(练习如何处理边界条件,判断IP合法性)

    复原IP地址 力扣题目链接(opens new window) 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 ...

  5. 【LeetCode回溯算法#08】递增子序列,巩固回溯算法中的去重问题

    递增子序列 力扣题目链接(opens new window) 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2. 示例 1: 输入:nums = [4,6,7,7] ...

  6. 【LeetCode回溯算法#10】图解N皇后问题(即回溯算法在二维数组中的应用)

    N皇后 力扣题目链接(opens new window) n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 给你一个整数 n ,返回所有不同的 n 皇 ...

  7. LeetCode46 回溯算法求全排列,这次是真全排列

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode的26篇文章,我们来实战一下全排列问题. 在之前的文章当中,我们讲过八皇后.回溯法,也提到了全排列,但是毕竟没有真正写 ...

  8. LeetCode通关:连刷十四题,回溯算法完全攻略

    刷题路线:https://github.com/youngyangyang04/leetcode-master 大家好,我是被算法题虐到泪流满面的老三,只能靠发发文章给自己打气! 这一节,我们来看看回 ...

  9. LeetCode:回溯算法

    回溯算法 这部分主要是学习了 labuladong 公众号中对于回溯算法的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 总结 概述 回溯是 DFS 中的一种技巧.回溯法采用 ...

  10. [LeetCode] 46. Int数组全排列 ☆☆☆(回溯)

    描述 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3]输出:[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2, ...

随机推荐

  1. [转帖]Arm CPU风起,补齐国产大芯片最后一块拼图 | 甲子光年

    https://rmh.pdnews.cn/Pc/ArtInfoApi/article?id=30960014 最近一年,国产CPU火了. 今年6月24日,龙芯中科在科创板挂牌上市,公司主营自研Loo ...

  2. [转帖]UseG1GC垃圾回收技术解析

    https://www.cnblogs.com/yuanzipeng/p/13374690.html 介绍 G1 GC,全称Garbage-First Garbage Collector,通过-XX: ...

  3. SingleNode HDFS 搭建过程

    背景 1. 纯粹测试 2. 未考虑安全和授权以及数据处理. 3. 单节点最简单的部署, 验证功能连接的可能性 资料获取以及环境变量的设置 获取最新的安装文件 https://downloads.apa ...

  4. 通过dotnet-dump分析生产环境docker容器部署的应用问题

    首先找到对应的docker id并exec进去,然后执行命令并更新apt包+下载procps和wget用于等下拉取dotnet-dump和查看线程 sed -i -e "s@deb.debi ...

  5. vim 从嫌弃到依赖(20)——global 命令

    在前面的文章中,我们介绍了如何进行查找和替换,而替换是建立在查找基础之上的一个简单的应用,它只是将匹配文本修改为另一个.那么vim中还能针对匹配上的文本做哪些操作呢?在本篇文章中我们来对这个问题进行探 ...

  6. TienChin 渠道管理-工程创建

    因为本文章主要围绕着项目开发进行,所以前言不做开头,直接上内容. 添加字段 我们的渠道表,我看到若依脚手架当中有一个是否删除的标志字段,所以我这里也添加一下: ALTER TABLE `tienchi ...

  7. C/C++ 实现枚举网上邻居信息

    在Windows系统中,通过网络邻居可以方便地查看本地网络中的共享资源和计算机.通过使用Windows API中的一些网络相关函数,我们可以实现枚举网络邻居信息的功能,获取连接到本地网络的其他计算机的 ...

  8. Python 实现SynFlood洪水攻击

    Syn-Flood攻击属于TCP攻击,Flood类攻击中最常见,危害最大的是Syn-Flood攻击,也是历史最悠久的攻击之一,该攻击属于半开放攻击,攻击实现原理就是通过发送大量半连接状态的数据包,从而 ...

  9. C++ Boost 文件系统相关函数

    基础处理 #include <iostream> #include <boost/foreach.hpp> #include <boost/filesystem.hpp& ...

  10. Linux-CentOS7 SSH免登陆

    配置三台服务器,如下: 生成密钥 在三台机器(node1\node2\node3)执行以下命令,生成公钥与私钥. ssh-keygen -t rsa 执行该命令之后,按下三个回车即可,然后敲(三个回车 ...