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

本题因为每个元素只能使用一次,所以我们需要下标来记录带开始的位置,其次本题特殊的地方在于保证递归子序列的递增性,所以我们在遍历时要进行判断是否满足递增,不满足的直接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);
- }
- }
- }
-
相关阅读:
setup.py文件简介
什么是多进程-多线程-多协程 ---- 文件系统
C++智能指针
普冉PY32系列(九) GPIO模拟和硬件SPI方式驱动无线收发芯片XL2400
视频文件转gif图片Movie To GIF使用
Learn-1
React redux更新数据的诡异特征==》彻底掌握redux更新state机制的精髓
【FFMPEG】解决截取MP4视频的中间段时,截取完成后前几帧视频卡住,但是有声音的情况
操作系统MIT6.S081:P8->Multiprocessors and locking
【网络安全】文件包含漏洞--使用session进行文件包含
-
原文地址:https://blog.csdn.net/weixin_51558481/article/details/127411849