zoukankan      html  css  js  c++  java
  • 47. Permutations II

    关联问题:排列1:46. Permutations, 排列2:47. Permutations II,组合:77. Combinations 

    问题:给定(存在重复元素)的数组,进行全排列,求出所有排列的可能性。

    Example 1:
    Input: nums = [1,1,2]
    Output:
    [[1,1,2],
     [1,2,1],
     [2,1,1]]
    
    Example 2:
    Input: nums = [1,2,3]
    Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
     
    Constraints:
    1 <= nums.length <= 8
    -10 <= nums[i] <= 10
    

      

    解法:Backtracking(回溯算法)

    两个变量:

    • 路径path:已经选择好的前几位结果
    • 选择列表:当前位置上元素的选择可能性:nums-visited
      • visited标记排除已经被选择过的元素。
      • nums所有元素。

    处理过程:

    base:递归退出条件:选择到最后一位结束,这里为已经选择好路径长度==给出的数组长度。

    做选择:对于当前位置,选择其中一个可用数字a。

      • 路径.add(a)
      • 选择列表.delete(a)->visited[i]=1

    撤销选择:回退到选择数字a之前的状况。

      • 路径.delete(a)
      • 选择列表.add(a)->visited[i]=0

    ⚠️  注意:本问题中,允许存在相同的元素,但是在排列中,相同元素在同一位置上的选择,是无效的。

    因此,我们需要排除相同元素在同一个位置上的选择。

    • 首先对nums进行排列,相同元素则会被连续排列。
    • 从第二个重复的元素开始,在同一个位置上的选择:
      • 若当前path中该重复的第一个元素已被使用,则当前的排序为全新排列,没有问题。
      • 若第一元素没有被使用visited[i-1]==0,则现在选择该重复元素,一定和之前的path选择中该位置使用了第一个元素的排列发生重复,需要跳过。

    代码参考:

     1 class Solution {
     2 public:
     3     void traverse(vector<vector<int>>& res, vector<int> nums, vector<int>& path, vector<int>& visited) {
     4         if(path.size() == nums.size()) {
     5             res.push_back(path);
     6             return;
     7         }
     8         for(int i = 0; i < nums.size(); i++) {
     9             if(visited[i]) continue;
    10             //该元素nums[i]已被使用在目前的path中,则跳过。
    11             if(i!=0 && nums[i]==nums[i-1] && !visited[i-1]) continue;
    12             //该元素nums[i],与还没被目前的path中使用的,排在它之前的元素重复,
    13             //(说明,上一个path的构造中,在同一个位置,一定已经使用过排在它之前的元素),则跳过。
    14             visited[i] = 1;
    15             path.push_back(nums[i]);
    16             traverse(res, nums, path, visited);
    17             path.pop_back();
    18             visited[i] = 0;
    19         }
    20         return;
    21     }
    22     vector<vector<int>> permuteUnique(vector<int>& nums) {
    23         vector<vector<int>> res;
    24         vector<int> path;
    25         vector<int> visited(nums.size(), 0);
    26         sort(nums.begin(), nums.end());
    27         traverse(res, nums, path, visited);
    28         return res;
    29     }
    30 };

    另,swap方法:

    参考:leetcode说明

    swap不需要恢复位置。与递归调用中重复元素的排除有关。

    代码参考:

     1 class Solution {
     2 public:
     3     void traverse(vector<vector<int>>& res, vector<int> nums, int pos) {
     4         if(pos == nums.size()) {
     5             res.push_back(nums);
     6             return;
     7         }
     8         for(int i = pos; i < nums.size(); i++) {
     9             if(i!=pos && nums[i]==nums[pos]) continue;
    10             swap(nums[i], nums[pos]);
    11             traverse(res, nums, pos+1);
    12         }
    13         return;
    14     }
    15     vector<vector<int>> permuteUnique(vector<int>& nums) {
    16         vector<vector<int>> res;
    17         sort(nums.begin(), nums.end());
    18         traverse(res, nums, 0);
    19         return res;
    20     }
    21 };
  • 相关阅读:
    程序员最好也要懂的一些沟通说服技巧
    MapFields和并行计算(OpenFOAM)
    Python 调用自己编写的Class
    Ubuntu 图形桌面死机重启(机器不重启)
    Ubuntu 安装 Visual Studio Code
    Ubuntu图形界面和终端界面切换快捷键
    Linux直接在通过终端打开图片文件
    Linux新建环境变量快速切换到文件夹(export)
    Python文件读写(一)
    Dictonary(Python)(一)
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/14225946.html
Copyright © 2011-2022 走看看