Leetcode47 Permutations II

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

Solution1

  • 回溯法解决,但是要注意本轮循环要跳过已经使用过的重复的数字。
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length==0) return result;
        List<Integer> temp = new ArrayList<Integer>();
        HashSet<Integer> used = new HashSet<Integer>();
        help(nums,used,temp,result);
        return result;
    }
    public void help(int[] nums,HashSet<Integer> used,List<Integer>temp,List<List<Integer>>result){
        if(temp.size()==nums.length){
            result.add(temp);
            return;
        }
        HashSet<Integer> duplicate = new HashSet<Integer>();
        for(int i=0;i<nums.length;i++){
            if(used.contains(i)) continue;//如果这个位置上的数已经被用过了,则往下再搜寻
            if(duplicate.contains(nums[i])) continue;//重复的数,在本次位置上不能再使用
            HashSet<Integer> usedTemp = new HashSet<Integer>(used);
            usedTemp.add(i);//这里是存储下标
            duplicate.add(nums[i]);//这里是存储数值
            List<Integer> temp1 = new ArrayList<Integer>(temp);
            temp1.add(nums[i]);
            help(nums,usedTemp,temp1,result);
        }        
    }
}

Solution2

  • 另一种类型的回溯。
public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        //Arrays.sort(nums);
        permuteUnique2(nums,0,result);
        return result;
    }
    public void permuteUnique2(int[] nums,int start,List<List<Integer>> result){
        if(start>=nums.length){
            List<Integer> item = new ArrayList<Integer>();
            for(int num:nums) item.add(num);
            result.add(item);
            return;
        }
        HashSet<Integer> used = new HashSet<Integer>();
        for(int i=start;i<nums.length;i++){
            if(used.contains(nums[i])) continue;
            int temp = nums[i];
            nums[i] = nums[start];
            nums[start] = temp;
            used.add(nums[start]);
            permuteUnique2(nums,start+1,result);
            nums[start] = nums[i];
            nums[i] = temp;      
        }
    }
}

Solution3

  • Leetcode46 Permutations中的解法4一样,这里仍然可以用插入法来求解,但是要复杂得多。这里插入数的时候不是以单个数为单位,而是以所有重复的数字为单位。
public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        result.add(new ArrayList<Integer>());
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            int count = 1;
            for(;i+1<nums.length&&nums[i+1]==nums[i];i++,count++);//统计重复的数字个数
            int size = result.size();
            for(int j=0;j<size;j++) insert(result.get(j),count,nums[i],result);
            while(size-->0) result.remove(0);
        }
        return result;
    }
    public void insert(List<Integer> item,int count,int num,List<List<Integer>> result){//将重复的数字插入已有的结果中
        Stack<Integer> stack = new Stack<Integer>();
        while(true){
            for(int index=stack.empty()?0:stack.peek()+1;count>0;index++,count--){//插入
                stack.push(index);
                item.add(index,num);
            }
            result.add(new ArrayList<Integer>(item));
            int i = stack.pop();
            item.remove(i);
            count++;
            for(;i==item.size();count++){//回溯
                if(stack.empty()) return;
                i = stack.pop();
                item.remove(i);
            }
            stack.push(i+1);//回溯成功后往后挪一个位置再插入
            item.add(i+1,num);
            count--;
        }
    }
}
  • 思路较复杂,不推荐此算法。

Solution4

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        while(true){
            List<Integer> item = new ArrayList<Integer>();
            for(int num:nums) item.add(num);
            result.add(item);
            int i,j;
            for(i=nums.length-1;i>0;i--) if(nums[i-1]<nums[i]) break;
            if(i<=0) break;
            for(j=nums.length-1;j>0;j--) if(nums[j]>nums[i-1]) break;
            int temp = nums[j];
            nums[j] = nums[i-1];
            nums[i-1] = temp;
            for(j = nums.length-1;i<j;i++,j--){
                temp = nums[j];
                nums[j] = nums[i];
                nums[i] = temp;
            }
        }
        return result;
    }
}
  • 思路清晰易懂,并且还复用性还非常高。不管是有重复数字还是没有重复数字都可以用这种方法求解。所以比回溯法更值得推荐。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值