文章目录

  • 46. 全排列
  • 47. 全排列 II
  • 78. 子集

46. 全排列

【回溯】排列树和子集树_数据结构

【回溯】排列树和子集树_leetcode_02

class Solution {
public:
    vector<vector<int>> ans;

    void fun(vector<int>& nums, int startIdx, int n) {
        if (startIdx == n) {
            ans.emplace_back(nums);
            return;
        }
        for(int i = startIdx; i < n; i++){
            swap(nums[startIdx], nums[i]);
            fun(nums, startIdx + 1, n);     // 表示已经放好了startIdx位置,现在需要放好startIdx + 1的位置
            swap(nums[startIdx], nums[i]);
        }
    }

    vector<vector<int>> permute(vector<int>& nums) {
        fun(nums, 0, nums.size());
        return ans;
    }
};

47. 全排列 II

【回溯】排列树和子集树_全排列_03

对于全排列去重问题,我们在每个节点都要遍历所有的元素,如果使用过了,就跳过,没使用过就要去重

【回溯】排列树和子集树_全排列_04

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    vector<bool> used;
    vector<int> nums;
    int n;

    void dfs(int level){
        if(level == n){
            ans.push_back(path);
            return;
        }
        for(int i = 0; i < n; i++){
        	// 同一树层去重:对于同一层,相同的元素之间若前面的元素没使用,后面的元素也不要使用
            if(used[i] || (i > 0 && !used[i - 1] && nums[i] == nums[i - 1])) continue;
            used[i] = true;
            path.push_back(nums[i]);
            dfs(level + 1);
            path.pop_back();
            used[i] = false;
        }
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        this->nums = nums;
        n = nums.size();
        used.resize(n, false);
        dfs(0);
        return ans;
    }
};

树层去重和树枝去重

78. 子集

【回溯】排列树和子集树_数据结构_05

【回溯】排列树和子集树_算法_06


求子集时,每个节点都要收集path

下一层横向增长的时,需要往i之后增长,而不是往startIdx后增长

for循环从startIdx开始,控制横向增长

递归调用,用i + 1控制纵向增长

如果纵向增长时,传入fun(startIdx + 1),会导致每层增长的结果都一样

【回溯】排列树和子集树_全排列_07

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    
    void fun(int startIndex, const vector<int>& nums){
        ans.push_back(path);
        for(int i = startIndex; i < nums.size(); i++){
            path.push_back(nums[i]);
            fun(i + 1, nums);    // 下一层横向增长的时,需要往i之后增长,而不是往startIdx后增长
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        fun(0, nums);
        return ans;
    }
};