• 47. Permutations II


    原题链接

    47. Permutations II

    题目描述

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

    示例 1:
    输入:nums = [1,1,2]
    输出:
    [[1,1,2],
     [1,2,1],
     [2,1,1]]
    
    
    示例 2:
    输入: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

    问题分析

    这是一道求全排列的问题,之前有一道和这道题类似的题,那道题中不存在重复的数字,见 46. Permutations

    先简单回顾一下之前求全排列的方法,即 46. Permutations 的解法,就是一道标准的递归题,代码如下所示:

    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector<vector<int>> res;
            helper(nums, 0, res);
            return res;
        }
    
        void helper(vector<int>& nums, int start, vector<vector<int>>& res){
            if(start == nums.size()){
                res.push_back(nums);
                return;
            }
    
            for(int i = start; i < nums.size(); i++){
                swap(nums[start], nums[i]);
                helper(nums, start+1, res);
                swap(nums[start], nums[i]);
            }
        }
    
        void swap(int& a, int& b){
            int tmp = a;
            a = b; 
            b = tmp;
        }
    };
    

    具体分析如下,假如我们现在需要求的是 {1,2,3} 的全排列,那么过程如下:

    • 先把1固定在第一位,然后递归求后面 {2,3} 的全排列
    • 把1和后面的每一位交换,然后求后面剩下的全排列,递归完成记得交换回来,保证下次交换之前恢复原样,该过程如下:
      • 交换1和2,得到 {2, 1, 3},递归求解 {1,3}的全排列,递归完成后交换回来,恢复原样{1, 2, 3}
      • 交换1和3,得到 {3, 2, 1},递归求解 {2,1}的全排列,递归完成后交换回来,恢复原样{1, 2, 3}
      • 递归的过程跟本次过程一样

    现在假设序列中出现了一个重复数字,例如序列 {1, 2, 3, 2},为了区分其中的两个2,我们给它们分别取一个下标,于是序列可以表示成 {1, 2a, 3, 2b}

    依然按照上面的方法,我们发现,存在以下2个情况:

    • 1和2a交换,得到 {2a, 1, 3, 2b},然后递归求 {1, 3, 2b} 的全排列
    • 1和2b交换,得到 {2b, 2a, 3, 1},然后递归求 {2a, 3, 1} 的全排列

    但是我们会发现,{1, 3, 2b}的全排列{2a, 3, 1}的全排列 是会重复的,问题出在哪呢?

    仔细思考会发现,1和后面两个2交换效果其实是一样的,这势必会导致两次交换后会出现相同的全排列,为了解决这个问题,我们需要在一轮交换过程中排除那些重复的交换。

    所以我们借助一个set(集合)来解决,于是,在存在相同数字的序列中求全排列的方法为:

    class Solution {
    public:
        vector<vector<int>> permuteUnique(vector<int>& nums) {
            vector<vector<int>> res;
            helper(nums, 0, res);
            return res;
        }
    
        void helper(vector<int>& nums, int start, vector<vector<int>>& res){
            if(start == nums.size()){
                res.push_back(nums);
                return;
            }
    
            unordered_set<int> history;
            for(int i = start; i < nums.size(); i++){
                if(history.count(nums[i])) continue;
                history.insert(nums[i]);
                
                swap(nums[start], nums[i]);
                helper(nums, start+1, res);
                swap(nums[start], nums[i]);
            }
        }
    
        void swap(int& a, int& b){
            int tmp = a;
            a = b; 
            b = tmp;
        }
    };
    

    和之前的代码对比,发现只有下面几行代码不一样

    unordered_set<int> history;
    for(int i = start; i < nums.size(); i++){
        if(history.count(nums[i])) continue;
        history.insert(nums[i]);
    
    只有0和1的世界是简单的
  • 相关阅读:
    nginx 按天生成日志
    cmder
    EXCEL最大行数问题:org.apache.xmlbeans.impl.store.Saver$TextSaver.resize(Saver.java:1700)
    nginx configure 错误记录
    Flume NetCat Demo
    Flume
    hbase
    kafka安装配置
    azkaban
    sqoop
  • 原文地址:https://www.cnblogs.com/nullxjx/p/14978558.html
Copyright © 2020-2023  润新知