算法训练(leetcode)第二十二天 | 491. 非递减子序列、全排列、47. 全排列 II

刷题记录

  • [491. 非递减子序列](#491. 非递减子序列)
  • [46. 全排列](#46. 全排列)
  • [47. 全排列 II](#47. 全排列 II)

491. 非递减子序列

leetcode题目地址

本题对于去重是一个难点,因为题目不允许排序,所以需要加一个笔记数组来判断相同的元素在同一层是否已经使用。使用set、map都可以达到这个目的。

时间复杂度: O ( n ∗ 2 n ) O(n * 2^n) O(n∗2n)
空间复杂度: O ( n ) O(n) O(n)

cpp 复制代码
// c++
class Solution {
public:
    vector<int> cur;
    void backtracking(vector<vector<int>> &result, const vector<int>& nums, int left){
        if(cur.size()>1){
            result.emplace_back(cur);
        }
        // 负责本层的去重
        unordered_set<int> uset;
        for(int i=left; i<nums.size(); i++){
            // 去重
            if(uset.find(nums[i])!=uset.end()) continue;
            if(cur.size()==0 || cur[cur.size()-1] <= nums[i]) {
                cur.emplace_back(nums[i]);
                uset.insert(nums[i]);
                backtracking(result, nums, i+1);
                cur.pop_back();
            }

        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        vector<vector<int>> result;
        backtracking(result, nums, 0);
        return result;
    }
};

46. 全排列

leetcode题目地址

全排列无需记录起始位置(每层都是从头开始找未使用过的元素),只需要控制每个元素在每个排列中只使用一次。借助一个额外的数组或map来实现。

时间复杂度: O ( n ! ) O(n!) O(n!)
空间复杂度: O ( n ) O(n) O(n)

cpp 复制代码
// c++
class Solution {
public:
    vector<int> cur;
    unordered_map<int, int> used;
    
    void backtracking(vector<vector<int>>&result, const vector<int>& nums){
        if(cur.size()==nums.size()){
            result.emplace_back(cur);
            return;
        }
        for(int i=0; i<nums.size(); i++){
            if(!used[i]){
                cur.emplace_back(nums[i]);
                used[i] = 1;
                backtracking(result, nums);
                used[i] = 0;
                cur.pop_back();
            }
            
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        backtracking(result, nums);
        return result;
    }
};

47. 全排列 II

leetcode题目地址

本题在上一题的基础上加入了相同的元素,因此需要对相同元素发起的全排列进行去重,有两种写法,一种是借助一个数组或容器来标识当前层是否已经使用了与当前元素相同的元素;另一种是排序过后判断前一个搜索过的元素与当前元素是否相同。

时间复杂度: O ( n ! ∗ n ) O(n! * n) O(n!∗n)
空间复杂度: O ( n ) O(n) O(n)

去重写法一

cpp 复制代码
// c++
class Solution {
public:
    vector<int> cur;
    // 纵向 标识单个排列中当前元素是否使用
    unordered_map<int, int> used;
    void backtracking(vector<vector<int>>&result, const vector<int>& nums){
        if(cur.size() == nums.size()){
            result.emplace_back(cur);
            return;
        }
        // 横向 标识所有排列中与当前元素相同的值是否已经参加过查找
        unordered_set<int> duplicate;
        for(int i=0; i<nums.size(); i++){
            if(!used[i] && duplicate.find(nums[i])==duplicate.end()){
                used[i] = 1;
                duplicate.insert(nums[i]);
                cur.emplace_back(nums[i]);
                backtracking(result, nums);
                cur.pop_back();
                used[i] = 0;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        backtracking(result, nums);
        return result;
    }
};

去重写法二

cpp 复制代码
// c++
class Solution {
public:
    vector<int> cur;
    // 纵向 标识单个排列中当前元素是否使用
    unordered_map<int, int> used;
    void backtracking(vector<vector<int>>&result, const vector<int>& nums){
        if(cur.size() == nums.size()){
            result.emplace_back(cur);
            return;
        }
    
        for(int i=0; i<nums.size(); i++){
           
            if(i>0 && nums[i]==nums[i-1] && used[i-1]) continue;
            if(!used[i]){
                used[i] = 1;
                cur.emplace_back(nums[i]);
                backtracking(result, nums);
                cur.pop_back();
                used[i] = 0;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end()); // 排序
        vector<vector<int>> result;
        backtracking(result, nums);
        return result;
    }
};
相关推荐
大明者省4 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
白狐_7986 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2586 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
ShineWinsu6 小时前
对于C++:C++11中lambda、function、bind的解析
c++·面试·笔试·开发·lambda·bind·function
码匠许师傅7 小时前
【C++ 面试真题】聊聊 C++ 的拷贝构造与拷贝赋值
java·c++·面试
Shell运维手记7 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
杨航 AI7 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
船厂电气自动化ai大模型8 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光8 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
汉字萌萌哒8 小时前
2024CSP-J入门级C++真题详解
开发语言·c++