今天学习回溯的全排列问题,分为两种:一种包含重复元素,一种不包含重复元素。

本题因为每个元素只能使用一次,所以我们需要下标来记录带开始的位置,其次本题特殊的地方在于保证递归子序列的递增性,所以我们在遍历时要进行判断是否满足递增,不满足的直接continue。回溯三部曲:
public void backtraveling(int[] nums,int startIndex)
- if(path.size()>1){
- res.add(new ArrayList(path));
- }
- int[] used = new int[201];
- for(int i=startIndex;i
- //树层去重
- if(!path.isEmpty()&&nums[i]
1)||used[nums[i]+100]==1){ - continue;
- }
- path.add(nums[i]);
- used[nums[i]+100]=1;
- backtraveling(nums,i+1);
- path.remove(path.size()-1);
- }
整体代码:
- List
> res = new ArrayList();
- List
path = new ArrayList(); - public List
> findSubsequences(int[] nums) {
- backtraveling(nums,0);
- return res;
- }
- public void backtraveling(int[] nums,int startIndex){
- if(path.size()>1){
- res.add(new ArrayList(path));
- }
- int[] used = new int[201];
- for(int i=startIndex;i
- //树层去重
- if(!path.isEmpty()&&nums[i]
1)||used[nums[i]+100]==1){ - continue;
- }
- path.add(nums[i]);
- used[nums[i]+100]=1;
- backtraveling(nums,i+1);
- path.remove(path.size()-1);
- }
- }
2.力扣46(全排列)

本题难点在于去重的操作,其他步骤和收集叶子节点的问题一样,只需要在尾节点处添加收集path即可,而我们怎么去重呢?也很简单,我们先定义一个used数组,我们在进行下次for循环时需要used【i】==true时,证明此元素使用过,就直接continue就可以达到去重了。回溯三部曲:
- 递归函数参数:首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,也就是从0开始,所以处理排列问题就不用使用startIndex了。
public void backtravling(int[] nums)
- 递归终止条件:当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。
- if(path.size()==nums.length){
- res.add(new ArrayList(path));
- return;
- }
- 单层搜索的逻辑:因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。
- for(int i=0;i
- if(used[i]){
- continue;
- }
- path.add(nums[i]);
- used[i]=true;
- backtravling(nums);
- used[i] = false;
- path.remove(path.size()-1);
- }
整体代码:
- List
> res = new ArrayList();
- List
path = new ArrayList(); - boolean[] used;
- public List
> permute(int[] nums) {
- used = new boolean[nums.length];
- Arrays.fill(used,false);
- backtravling(nums);
- return res;
- }
- public void backtravling(int[] nums) {
- if(path.size()==nums.length){
- res.add(new ArrayList(path));
- return;
- }
- for(int i=0;i
- if(used[i]){
- continue;
- }
- path.add(nums[i]);
- used[i]=true;
- backtravling(nums);
- used[i] = false;
- path.remove(path.size()-1);
- }
- }
3.力扣47(全排列II)

本题是对上一个全排列问题的升级版,因为给我们的数组是包含重复元素的,所以我们不仅需要使用used【i】==true时跳过,我们还需要使用 i>0&&nums[i]==nums[i-1]&&!used[i-1]条件,若满足就跳过,也就是说我们在树层遍历时,碰到相同元素时,前面的元素的used【i-1】==false时跳过。
整体代码:
- List
> res = new ArrayList();
- List
path = new ArrayList(); - boolean[] used;
- public List
> permuteUnique(int[] nums) {
- used = new boolean[nums.length];
- Arrays.fill(used,false);
- Arrays.sort(nums);
- backtraveling(nums);
- return res;
- }
- public void backtraveling(int[] nums) {
- if(path.size()==nums.length){
- res.add(new ArrayList(path));
- return;
- }
- for(int i=0;i
- if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false){
- continue;
- }
- if(!used[i]){
- path.add(nums[i]);
- used[i] = true;
- backtraveling(nums);
- used[i] = false;
- path.remove(path.size()-1);
- }
- }
- }
-
相关阅读:
2006-2020年各省研发投入强度
定位OOM(Out of Memory)
山与路远程控制 一个基于electron和golang实现的远控软件
使用C语言实现双向链表(带头结点)
思维导图软件Xmind mac中文特点介绍
QNX Typed memory介绍
jQuery使用echarts循环插入图表
300分钟吃透分布式缓存-08讲:MC系统架构是如何布局的?
C# OpencvSharp异常FileNotFoundException具体解决办法
C语言十进制转其它进制
-
原文地址:https://blog.csdn.net/weixin_51558481/article/details/127411849
-
最新文章
-
沪漂五周年了:我越来越迷茫了
Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
MySQL-Seconds_behind_master的精度误差
[MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
Agent OS :五种驯服不确定性的范式
PortSwigger SQL注入LAB11
数据库即时编译JIT
[Begin]AI Learn Data Day 0
深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU