Leetcode - Permutation II

原题链接:[url]https://leetcode.com/problems/permutations-ii/[/url]
[分析] 同Permutation一题的区别在于输入数组可能包含重复元素,在面试时即使面试官没有明确指出也该想到。如何处理重复元素不致得到重复结果呢?基本思路是排序然后跳过重复元素。Method1 每次循环递归都要排序且要复制一次数组,时间和空间消耗都比较大,Method2是Code Ganker大神的思路,使用一个额外数组used表示元素是否已经被排好位置。去重的关键是for循环一开始的if判断,理解起来有些费劲,大神的解释:只对第一个未被使用的进行递归,如果第一个重复元素前面的元素还没在当前结果中,那么我们不需要进行递归,这一次结果会出现在第一个的递归函数结果中。举例理解下:假设元素 a 有重复, 下标 i 和 i-1 处均是 a, 处理 i 下标时发现 i-1 下标的 a 还未被使用,这种情况下 i 应当跳过,因为循环是从前往后的推进的,i-1 已先被循环处理过,在这层递归中假设元素将排在位置 k 处,则若不跳过 i ,i 也被放在位置 k 处,最终将导致结果重复。

[ref] Code Ganker大神博客
[url]http://blog.youkuaiyun.com/linhuanmars/article/details/21570835[/url]


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

public List<List<Integer>> permuteUnique(int[] num) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(num == null || num.length == 0)
return result;
Arrays.sort(num);
return permutate(num, 0);
}

private List<List<Integer>> permutate(int[] num, int beg){
List<List<Integer>> result = new ArrayList<List<Integer>>();
if(beg == num.length - 1){
List<Integer> item = new ArrayList<Integer>();
item.add(num[beg]);
result.add(item);
return result;
}

int origin = num[beg];
for(int i = beg; i < num.length; i++){
if(i != beg && num[i] == num[i - 1])
continue;
num[beg] = num[i];
num[i] = origin;

int[] sub = Arrays.copyOf(num, num.length);
Arrays.sort(sub, beg + 1, num.length);

for(List<Integer> item : permutate(sub, beg + 1)){
item.add(0, num[beg]);
result.add(item);
}
num[i] = num[beg];
num[beg] = origin;
}
return result;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值