Leetcode刷题系列(一)Subsets 与 Permutation

原创 2016年05月30日 22:58:26

  Subsets与Permutation这两种题型如果用Recursion的方法来解决,其思路是及其相似的。

1.Subsets I

内容

Given a set of distinct integers, S, return all possible subsets.

Note:
Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.
For example,If S = [1,2,3], a solution is:

[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

思路

  这道题是求一个集合的所有子集,对于集合中的每个元素有两种选择,放进集合中和不放进集合中。可以用树型结构表示该过程。

  另外,由于递归无法有返回值,每个子集(ArrayList<Integer>)在递归过程中可以作为参数加到最后的结果(ArrayList<ArrayList<Integer>>)中。这种情况在使用Java语言的递归中尤其常见。

代码

public class Solution {
    public ArrayList<ArrayList<Integer>> subsets(int[] num) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if(num == null || num.length == 0) {
            return result;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        Arrays.sort(num);  
        subsetsHelper(result, list, num, 0);
        return result;
    }

    private void subsetsHelper(ArrayList<ArrayList<Integer>> result,
        ArrayList<Integer> list, int[] num, int pos) {
        result.add(new ArrayList<Integer>(list));
        for (int i = pos; i < num.length; i++) {
            list.add(num[i]);
            subsetsHelper(result, list, num, i + 1);
            list.remove(list.size() - 1);
        }
    }
}

重点  

  1. 前面的边界检查,如果不存在则返回空集。

  2. subsetsHelper则为递归程序,子集被当成参数传递使得递归过程中数据不会丢失,还可以在类中增加私有成员进行储存。
  3. for循环中的add和remove方法是关键,代表放进和不放进两种选择,这两个方法的位置可以看成是树形结构的向下走和往回走。

2.Subsets II

内容

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note:
Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.
For example,If nums = [1,2,2], a solution is:

[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

思路

  Subsets IISubsets I 的区别仅在于集合中存在重复元素。因此,如果使用 Subsets I 的方法就会导致最终的结果集中存在一些重复的子集(注意:集合中的元素之间是没有次序关系的)。

  此时在 Subsets I 的解题思路基础上,加一些特殊处理即可。以题干中的例子为例,将集合中的重复元素2特殊处理,在每一次的递归过程中要么取第一个2放进集合,要么所有的2都不选进集合中。

代码

  此处仅贴出与第一部分不同,即进行特殊处理的代码。

private void subsetsHelper(ArrayList<ArrayList<Integer>> result,
    ...
    for (int i = pos; i < num.length; i++) {
        if ( i != pos && num[i] == num[i - 1]) {
            continue;
        }    
        ...
    }
}

重点

  由于每次递归调用函数时,pos的值会变化,因此是可以把所有重复的2选进集合的,确保了存在2的子集的单一性和正确性。


3.Permutation I

内容

Given a collection of distinct numbers, return all possible permutations.

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

思路

  此题解题思路与上题很像,区别在与此题没有位置关系。换种说法,此题可以解读为给出几个元素,生成这些元素的排列组合,因此元素之间是没有位置关系的。

代码

public class Solution {
    public ArrayList<ArrayList<Integer>> permute(int[] num) {
         ArrayList<ArrayList<Integer>> rst = new ArrayList<ArrayList<Integer>>();
         if (num == null || num.length == 0) {
             return rst; 
         }

         ArrayList<Integer> list = new ArrayList<Integer>();
         helper(rst, list, num);
         return rst;
    }

    public void helper(ArrayList<ArrayList<Integer>> rst, ArrayList<Integer> list, int[] num){
        if(list.size() == num.length) {
            rst.add(new ArrayList<Integer>(list));
            return;
        }

        for(int i = 0; i<num.length; i++){
            if(list.contains(num[i])){
                continue;
            }
            list.add(num[i]);
            helper(rst, list, num);
            list.remove(list.size() - 1);
        }

    }
}

重点

 此代码在思路上与 Subsets 相似易于理解且在可以套用在Permutation II上。


4.Permutation II

内容

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].

思路

  主要特殊解决重复问题,与 Subsets II 极为相似。

代码

 代码与 Permutation I 一样,主要是下面这段代码解决了重复的问题。

public void helper(ArrayList<ArrayList<Integer>> rst, ArrayList<Integer> list, int[] num){
        ...
        for(int i = 0; i<num.length; i++){
            if(list.contains(num[i])){
                continue;
            }
            ...
        }
    }
}

5.总结

  1. 任何递归程序均可写成非递归的形式,一般可以有两种方式改写:使用编码方式、使用栈(最常用)。如果一个程序使用非递归形式易懂,那么应该使用非递归形式,因为递归形式毕竟有调用程序的开销。这里给出编码方式解决 Subsets I 的代码。

    class Solution {
        public ArrayList<ArrayList<Integer>> subsets(int[] nums) {
            ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
            int n = nums.length;
            Arrays.sort(nums);
    
            // 1 << n is 2^n
            // each subset equals to an binary integer between 0 .. 2^n - 1
            // 0 -> 000 -> []
            // 1 -> 001 -> [1]
            // 2 -> 010 -> [2]
            // ..
            // 7 -> 111 -> [1,2,3]
            for (int i = 0; i < (1 << n); i++) {
                ArrayList<Integer> subset = new ArrayList<Integer>();
                for (int j = 0; j < n; j++) {
                    // check whether the jth digit in i's binary representation is 1
                    if ((i & (1 << j)) != 0) {
                        subset.add(nums[j]);
                    }
                }
                result.add(subset);
            }       
            return result;
        }
    }
    
  2. 相似题型(后续补充)


leetcode 刷题之路 56 Subsets (非递归解法)

Given a set of distinct integers, S, return all possible subsets. Note: Elements in a subset...

LeetCode刷题笔录Subsets

自己总是写不出递归的方法,只能用f

【LeetCode】Subsets 系列

【LeetCode】Subsets 系列 78. Subsets 90. Subsets II

LeetCode刷题(C++)——Next Permutation(Medium)

Implement next permutation, which rearranges numbers into the lexicographically next greater permuta...

leetcode系列(45)Next Permutation

Implement next permutation, whichrearranges numbers into the lexicographically next greater permutat...
  • macchan
  • macchan
  • 2015年10月24日 15:19
  • 146

Leetcode刷题记——31. Next Permutation(下一个排列)

一、题目叙述: Implement next permutation, which rearranges numbers into...

leetcode第一刷_Permutation Sequence

这道题还挺好的,如果你的思路是每次生成一个全排列,然后累计到k次,那么停下来吧,肯定超时了亲。。 微软今年的笔试题里有一道类似的,我之前已经提到过了,是只有0和1的字符串,求第k个排列是什么样子的。...

Leetcode刷题记—— 60. Permutation Sequence(排列序列)

一、题目叙述: The set [1,2,3,…,n] contains a total of n! unique permutati...

60. Permutation Sequence\78. Subsets\77. Combinations

Permutation Sequence 题目描述 代码实现 Subsets 题目描述 代码实现 Combinations 题目描述 代码实现60. Permutation Sequence题目描述T...

LeetCode OJ算法题(三十):Next Permutation

题目: Implement next permutation, which rearranges numbers into the lexicographically next greate...
  • op_yu
  • op_yu
  • 2014年07月24日 21:29
  • 248
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Leetcode刷题系列(一)Subsets 与 Permutation
举报原因:
原因补充:

(最多只允许输入30个字)