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;
                }
            }
        }
    }
  • 相关阅读:
    @ExceptionHandler
    使用Vue.extend实现iview Upload在单文件上传时,拖拽多个文件给出错误提示
    spring 常用的注入方式
    SpringMVC框架
    Redis
    事务的隔离性以及隔离级别
    Qt的获取和安装
    C++ 指针delete 及 指针delete后赋值为NULL
    图形流水线
    freeglut的安装步骤
  • 原文地址:https://www.cnblogs.com/airwindow/p/4749457.html
Copyright © 2011-2022 走看看