【算法训练 day31 非递减子序列、全排列、全排列Ⅱ】


一、非递减子序列-LeetCode 491

Leecode链接: leetcode 491
文章链接: 代码随想录
视频链接: B站

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

思路

本体不能使用排序,因为题目求的就是递增序列。并且题目中还有重复元素,这就意味着需要去重,这里只能使用哈希数组来标记元素是否出现过来判断是否出现重复元素。

实现代码

//cpp
class Solution {
public:
	vector<vector<int>>res;
	vector<int>path;

	void test(vector<int>& nums,int index){
		if(path.size() >= 2){
			res.push_back(path);//这里不加 return,因为加了就回退了
		}
		vector<int> hash[201] = {0};
		for(int i = index;i<nums.size();i++){
			if((!path.empty() && nums[i] < path.back()) || hash[nums[i] + 100] == 1){
				continue;
			}
			hash[nums[i] + 100] = 1;
			path.push_back(nums[i]);
			test(nums,i+1);
			path.pop_back();
		}
	}
    vector<vector<int>> findSubsequences(vector<int>& nums) {
		res.clear();
		path.clear();
		test(nums,0);
		return res;
    }
};

个人问题

不熟悉使用数组进行去重。

总结

整体难度中等,把握好哈希数组什么时候发挥作用,题目要求的是不能出现重复组合,又不能排序进行去重,所以这个哈希数组在每一层都需要重新设置为0,这样就能保证不同的递归层所有元素都是未被取到的状态,相同递归层保存了取到相同元素的状态。又因为每次传入递归的index参数都是i+1,一定不是本身,做到了去除本身的目的。


二、全排列-LeetCode 46

Leecode链接: LeetCode 46
文章链接: 代码随想录
视频链接: B站

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例:

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

思路

题目求全排列,所以每次递归时,index不能取i+1,因为这样就不能在取第二个元素时取第一个元素了,所以i默认初始为0。

实现代码

快慢指针(滑动窗口)

//cpp
class Solution {
public:
    vector<int>path;
    vector<vector<int>>res;

    void permu(vector<int>& nums,vector<bool>& uset){
        if(path.size()==nums.size()){
            res.push_back(path);
            return;
        }

        
        for(int i = 0;i<nums.size();i++){
            if(uset[i] == true){
                continue;
            }
            uset[i] = true;
            path.push_back(nums[i]);
            permu(nums,uset);
            path.pop_back();
            uset[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        res.clear();
        path.clear();
        vector<bool> uset(nums.size(),false);
        permu(nums,uset);
        return res;
    }
};

个人问题

无。

总结

简单题,这题与非递减子序列中都用到了数组来标记是否用到元素,区别是一个是局部变量,一个是作为引用参数传递,作用类似全局变量。具体该用哪个时可以画个图来判断。


三.全排列Ⅱ-LeeCode 47

Leecode链接: LeetCode 47
文章链接: 代码随想录
视频链接: B站

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

示例:

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

思路

题目有重复元素,老规矩使用数组来标记元素去重。思路基本与全排列类似,先进行排序,保证相同元素相邻。

实现代码

//cpp
class Solution {
public:

    vector<int>path;
    vector<vector<int>>res;

    void permu(vector<int>& nums,vector<bool>& uset){
        if(path.size() == nums.size())
        {
            res.push_back(path);
            return;
        }

        for(int i = 0;i<nums.size();i++){
            if(i>0&&nums[i] == nums[i-1]&&uset[i-1] == false){
                continue;
            }
            if(uset[i] == true){
                continue;
            }
            uset[i] = true;
            path.push_back(nums[i]);
            permu(nums,uset);
            path.pop_back();
            uset[i] = false;

            /*if (uset[i] == false) {
                uset[i] = true;
                path.push_back(nums[i]);
                permu(nums, uset);
                path.pop_back();
                uset[i] = false;
            }*/

        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        path.clear();
        res.clear();
        vector<bool> uset(nums.size(),false);
        sort(nums.begin(),nums.end());
        permu(nums,uset);
        return res;
    }
};

个人问题

无。

总结

本体与全排列不同的是,由于有重复元素,且每次取元素都默认从数组的第一个元素开始遍历,这就导致可能会取到自身元素,解决办法很简单,加一句if(hash[i] == 1)continue,这句就代表在上一层递归中,该元素已经被使用过了。

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值