zoukankan      html  css  js  c++  java
  • [LeetCode#47]Permutations II

    Problem:

    Given a collection of numbers that might contain duplicates, return all possible unique permutations.

    For example,
    [1,1,2] have the following unique permutations:
    [1,1,2][1,2,1], and [2,1,1].

    Analysis:

    This problem is very very typical to caculate permutation!!!
    It involves many coding skills as combination problem. But it also possess some distinct characteristics to to distinguish itself out.
    
    Basic idea:
    At each state(position), we search out every possible routines. Some routinies should be avoided during the explore process.
    case 1: The element has already been used.
    case 2: A element with the same value as other elements has already been placed at this position. Only one of them could be placed at this position, to avoid duplicates in the result set. 
    
    Skill:
    1.a  use a boolean array to record if a element has already been used.
    boolean[] used = new boolean[nums.length];
    
    1.b  sort the nums array, to avoid duplicates by taking advantage of sorted form. 
    Note: since we need to permutate the array, rearrange the elements' order would not affect final result. 
    Arrays.sort(nums);
    
    Unlike in the combination problem, we start from a passed in index.
    for (int i = start; i < nums.length; i++)
    In this problem, the start has no meaning. we would try to place each elements into the current pos(position), and use some checking codition to avoid duplicates and replacement. 
    for (int i = 0; i < nums.length; i++) {
    ...
    }
    *************************************************
    The skill in avoid duplicate is quite tricky!!!
    ************************************************
    case 1: 2, 1, 1
    case 2: 2, 1(1), 1
    Apparently, we should have right mechanism to distinguish the above two cases.
    
    Principle: to avoid duplicate, at each position, if several availabel elements(has not been used) share the same value, we always place the first element at that position only!
    
    if (i > 0 && !used[i-1] && nums[i-1] == nums[i]) continue;
    a. firstly, we should guarantee the current element is not the first element, which has no previous element.
    b. secondly, we should make sure the nums[i-1] has no be used. Cause even "nums[i-1] == nums[i]", but it has already been used in the previous position. We don't need to take it into consideration. 
    if (!used[i]) {
        ....
    }
    This can guarantee it would never be used for the current position.
    
    Note: There is no obvious 'cut-off' for base case, we avoid the search along wrong direction at 
    for (int i = 0; i < nums.length; i++) {
        if (i > 0 && !used[i-1] && nums[i-1] == nums[i]) continue;
            ...
            helper(pos+1, nums, used, ret, path);
            ...
    }
    
    Thus when we reach "pos == nums.length", it means we get a right solution.
    The logic design is the same as "N-Quuens" problem.
        private void helper(int row, int n, int[] column_for_row, ArrayList<Integer> ret) {
            if (row == n) {
                ret.set(0, ret.get(0) + 1);
                return;
            }
            //a totally different way of thinking!!!!
            for (int i = 0; i < n; i++) {
                column_for_row[row] = i;
                if (isValid(row, column_for_row))
                    helper(row + 1, n, column_for_row, ret);
            }
        }

    Solution 1:

    public class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) {
            List<List<Integer>> ret = new ArrayList<List<Integer>> ();
            if (nums == null || nums.length == 0)
                return ret;
            ArrayList<Integer> path = new ArrayList<Integer> ();
            boolean[] used = new boolean[nums.length];
            Arrays.sort(nums);
            helper(0, nums, used, ret, path);
            return ret;
        }
        
        private void helper(int pos, int[] nums, boolean[] used, List<List<Integer>> ret, ArrayList<Integer> path) {
            if (pos == nums.length) {
                ret.add(new ArrayList<Integer> (path));
                return;
            }
            for (int i = 0; i < nums.length; i++) {
                if (i > 0 && !used[i-1] && nums[i-1] == nums[i]) continue;
                if (!used[i]) {
                    used[i] = true;
                    path.add(nums[i]);
                    helper(pos+1, nums, used, ret, path);
                    path.remove(path.size()-1);
                    used[i] = false;
                }
            }
        }
    }

    Improvement:

    Actually, for this problem, we could get the position information from the number of items in path.
    But the update would run more slower than directly pass around the position information.
    Thus the code could be changed into:

    Solution 2:

    public class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) {
            List<List<Integer>> ret = new ArrayList<List<Integer>> ();
            if (nums == null || nums.length == 0)
                return ret;
            ArrayList<Integer> path = new ArrayList<Integer> ();
            boolean[] used = new boolean[nums.length];
            Arrays.sort(nums);
            helper(nums, used, ret, path);
            return ret;
        }
        
        private void helper(int[] nums, boolean[] used, List<List<Integer>> ret, ArrayList<Integer> path) {
            if (path.size() == nums.length) {
                ret.add(new ArrayList<Integer> (path));
                return;
            }
            for (int i = 0; i < nums.length; i++) {
                if (i > 0 && !used[i-1] && nums[i-1] == nums[i]) continue;
                if (!used[i]) {
                    used[i] = true;
                    path.add(nums[i]);
                    helper(nums, used, ret, path);
                    path.remove(path.size()-1);
                    used[i] = false;
                }
            }
        }
    }
  • 相关阅读:
    python基础一 day40 守护线程
    python基础一 day40 线程复习
    python基础一 day39 线程探索
    python基础一 day39 复习-回调函数
    python基础一 day38 进程池代码
    python基础一 day38 进程间的数据共享
    python基础一 day38 管道
    python基础一 day18 认识正则表达式及探索
    python小白-day3 函数
    python小白-day3 深浅拷贝
  • 原文地址:https://www.cnblogs.com/airwindow/p/4749457.html
Copyright © 2011-2022 走看看