面试热点题:回溯算法 递增子序列与全排列 II

前言:
如果你一点也不了解什么叫做回溯算法,那么推荐你看看这一篇回溯入门,让你快速了解回溯算法的基本原理及框架

递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

来源:力扣(LeetCode)递增子序列
在这里插入图片描述
由题意可得下面两点要求:

  • 递增的子序列,且元素数量大于2
  • 子序列与子序列不能相同
  • 可使用重复出现的数字

像这种需要依次取元素,然后将元素存储起来汇成总集合,期间可能还需要回退取不一样集合的题目,我们第一个想到的可以使用回溯法,那么该如何回溯呢?且看下图分析:我们使用[ 4,7,6,7 ]举例
在这里插入图片描述
在这里插入图片描述

  1. 回溯收集子集条件
    根据题意可以得知,我们只要子序列的数量大于等于2就可以
  2. 回溯终止条件
    终止条件就是达到nums.size()
  3. 单层搜索逻辑
    我们由图可以得知,虽然序列里面可能有重复的数字,但是单层我们不能取相同的数字,如果我们取了相同的数字,那么必定会存在相同的子集,所以我们单层需要去重

单层去重我们这里使用一个标记的容器 unordered_set< int > use存放已经出现过的数字


代码如下:

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;

    void BackTracking(vector<int>& nums,int begin)
    {
    
    
        if(_arr.size()>=2)//只要数据>=2就存储,我们这里不需要return
        {
    
    
            arr.push_back(_arr);
        }
        unordered_set<int> use;//标记容器
        for(int i=begin;i<nums.size();i++)
        {
    
    
        //如果是空直接存放,然后判断别的关系
            if((!_arr.empty() && _arr.back()>nums[i]) || use.find(nums[i])!=use.end())
            {
    
    
                continue;
            }
            _arr.push_back(nums[i]);
            use.insert(nums[i]);
            BackTracking(nums,i+1);//不能重复使用单个数据,所以我们需要i+1
            _arr.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
    
    
        BackTracking(nums,0);
        return arr;
    }
};

全排列 II

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

来源:力扣(LeetCode)全排列 II

本题是全排列的进阶版,之前是没有重复元素,现在有重复元素,我们该如何解决呢?

在这里插入图片描述
这个题与上一题递增子序列相差不多,也是需要单层去重,且看下图:
在这里插入图片描述
相较于之前的收集元素,排列我们需要将每个元素都使用到,所以我们每次循环开始条件都为0,但是为了不使用一个使用过的元素,我们需要设置一个标记的数组,使用过一个标记一个,单层去重,是因为同一层使用相同的元素没有意义,使用相同元素,相当于递归两遍相同数据,导致出现相同子集

  • 先排序所有元素
  • 标记数组
  • 单层去重

代码如下:

class Solution {
    
    
public:
    vector<vector<int>> arr;
    vector<int> _arr;
    void BackTracking(vector<int>& nums,vector<bool>& use)
    {
    
    
        if(_arr.size()==nums.size())
        {
    
    
            arr.push_back(_arr);
            return;
        }
        for(int i=0;i<nums.size();i++)
        {
    
    
        	//单层去重,及判断元素是否使用过
            if(i>0 && nums[i]==nums[i-1] && use[i-1]==false)
            {
    
    
                continue;
            }
            if(use[i]==false)
            {
    
    
                use[i]=true;
                _arr.push_back(nums[i]);
                BackTracking(nums,use);
                _arr.pop_back();
                use[i]=false;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
    
    
        sort(nums.begin(),nums.end());//需要排序,为去重做准备
        vector<bool> use(nums.size(),false);
        BackTracking(nums,use);
        return arr;
    }
};

猜你喜欢

转载自blog.csdn.net/DEXTERFUTIAN/article/details/129799563
今日推荐