算法D29 | 回溯算法5|491.递增子序列 46.全排列 47.全排列 II

491.递增子序列

本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。

代码随想录

视频讲解:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili

一个是去重,一个是判断是否递增;去重发生在横向,递增发生在纵向。

横向去重需要额外构建一个集合。

Python:

python 复制代码
class Solution:
    def __init__(self):
        self.result = []
        self.path = []

    def backtracking(self, nums, start_index):
        if len(self.path)>=2:
            self.result.append(self.path[:])
        used_set = set()
        for i in range(start_index, len(nums)):
            if len(self.path)>=1 and nums[i]<self.path[-1]: # 纵向去重
                continue
            if nums[i] in used_set: # 横向去重
                continue                
            used_set.add(nums[i])
            self.path.append(nums[i])
            self.backtracking(nums, i+1)
            self.path.pop()
        return

    def findSubsequences(self, nums: List[int]) -> List[List[int]]:
        self.backtracking(nums, 0)
        return self.result

C++:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    
    void backtracking(vector<int>& nums, int startIndex) {
        if (path.size()>=2) result.push_back(path);
        unordered_set<int> uset;
        for (int i=startIndex; i<nums.size(); i++) {
            if (uset.find(nums[i])!=uset.end()) continue;
            if (!path.empty() && nums[i]<path.back()) continue;
            uset.insert(nums[i]);
            path.push_back(nums[i]);
            backtracking(nums, i+1);
            path.pop_back();
        }
        return;
    }

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

46.全排列

本题重点感受一下,排列问题 与 组合问题,组合总和,子集问题的区别。 为什么排列问题不用 startIndex

代码随想录

视频讲解:组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列_哔哩哔哩_bilibili

Python:

python 复制代码
class Solution:
    def __init__(self):
        self.result = []
        self.path = []

    def backtracking(self, nums, k):
        if len(self.path)==k:
            self.result.append(self.path[:])
        for i in range(len(nums)):
            self.path.append(nums[i])
            new_nums = nums[:i] + nums[i+1:]
            self.backtracking(new_nums, k)
            self.path.pop()
        return
    
    def permute(self, nums: List[int]) -> List[List[int]]:
        k = len(nums)
        self.backtracking(nums, k)
        return self.result

C++:

用指针实现标记是否使用过,更为节省内存和时间。

cpp 复制代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;

    void backtracking(vector<int>& nums, vector<bool>& used) {
        if (path.size()==nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i=0; i<nums.size(); i++) {
            if (used[i] == true) continue;
            used[i] = true;
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
        return;
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;    
    }
};

47.全排列 II

本题 就是我们讲过的 40.组合总和II 去重逻辑 和 46.全排列 的结合,可以先自己做一下,然后重点看一下 文章中 我讲的拓展内容。 used[i - 1] == true 也行,used[i - 1] == false 也行

代码随想录

视频讲解:回溯算法求解全排列,如何去重?| LeetCode:47.全排列 II_哔哩哔哩_bilibili

Python:

python 复制代码
class Solution:
    def __init__(self):
        self.result = []
        self.path = []

    def backtracking(self, nums, used):
        if len(self.path) == len(nums):
            self.result.append(self.path[:])
            return
        uset = set()
        for i in range(len(nums)):
            if used[i]: continue        # 纵向去重
            if nums[i] in uset: continue # 横向去重
            uset.add(nums[i])
            used[i] = True
            self.path.append(nums[i])
            self.backtracking(nums, used)
            self.path.pop()
            used[i] = False
        return

    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        used = [False] * len(nums)
        self.backtracking(nums, used)
        return self.result
        

C++:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;

    void backtracking(vector<int>& nums, vector<bool>& used) {
        if (path.size()==nums.size()) {
            result.push_back(path);
        }
        unordered_set<int> uset;
        for (int i=0; i<nums.size(); i++) {
            if (uset.find(nums[i]) != uset.end()) continue;
            if (used[i]==true) continue;
            used[i] = true;
            uset.insert(nums[i]);
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
        return;
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;    
    }
};
相关推荐
我在人间贩卖青春3 分钟前
C++之继承的方式
c++·private·public·protected·继承方式
小瑞瑞acd9 分钟前
【小瑞瑞精讲】卷积神经网络(CNN):从入门到精通,计算机如何“看”懂世界?
人工智能·python·深度学习·神经网络·机器学习
仟濹10 分钟前
算法打卡day2 (2026-02-07 周五) | 算法: DFS | 3_卡码网99_计数孤岛_DFS
算法·深度优先
驭渊的小故事13 分钟前
简单模板笔记
数据结构·笔记·算法
火车叼位27 分钟前
也许你不需要创建.venv, 此规范使python脚本自备依赖
python
YuTaoShao28 分钟前
【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法一)前后缀分解
算法·leetcode·职场和发展
火车叼位34 分钟前
脚本伪装:让 Python 与 Node.js 像原生 Shell 命令一样运行
运维·javascript·python
VT.馒头34 分钟前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
goodluckyaa44 分钟前
LCR 006. 两数之和 II - 输入有序数组
算法
孤狼warrior1 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪