跳转至

47. 全排列 II

力扣链接(中等):https://leetcode.cn/problems/permutations-ii

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

示例 1:

Text Only
1
2
3
4
5
输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

示例 2:

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

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

个人题解

  • 注意排列和组合两类问题在 for 循环开始位置的区别;
  • 注意去重方式和组合总和 II的异同。
C++
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]) continue;
            // 这里的去重方式和 「组合总和 II」 写法不同,但原理是一样的
            // !used[i - 1] 的作用是排除上一次 for 中由于 used[i] == true 导致被跳过的情况
            // 如果 nums[i - 1] 在当前遍历路径上被使用,那么 used[i - 1] == true 就会被上一次 for continue 掉
            // 那么此时很显然即便满足 i && nums[i] == nums[i - 1],逻辑也是不对的,因为上一个元素都被 continue 了
            // 自然不存在所谓的层内重复,更好的方式是画一个树形图走一遍过程
            // 可以和 「组合总和 II」中 i > begin 的思想类比一下
            if(i && nums[i] == nums[i - 1] && !used[i - 1]) continue;

            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, used);
            used[i] = false;
            path.pop_back();
        }
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        // 首先排序,才能让相同元素相邻,判断和前一个数是否相等即可
        sort(nums.begin(), nums.end());
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};