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刷题笔录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...

LeetCode Permutation

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

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

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

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

题目: Implement next permutation, which rearranges numbers into the lexicographically next greate...
  • op_yu
  • op_yu
  • 2014-07-24 21:29
  • 227
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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