Leetcode46 Permutations

Permutations

Given a collection of 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].

Solution1

  • 典型的回溯问题,回溯问题一般说来用递归方法求解会比较简单
public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        HashSet<Integer> set = new HashSet<Integer>();
        permute(nums,set,new ArrayList<Integer>(),result);
        return result;
    }
    public void permute(int[] nums,HashSet<Integer> set,List<Integer> item,List<List<Integer>> result){
        if(item.size()==nums.length){
            result.add(item);
            return;
        }
        for(int i=0;i<nums.length;i++){
            if(set.contains(nums[i])) continue;
            List<Integer> temp = new ArrayList<Integer>(item);
            temp.add(nums[i]);
            HashSet<Integer> newSet = new HashSet<Integer>(set);
            newSet.add(nums[i]);
            permute(nums,newSet,temp,result);
        }        
    }
}

Solution2

  • 用迭代的方法来实现上述回溯过程如下:
public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length==0) return result;
        Stack<Integer> stack = new Stack<Integer>();
        HashSet<Integer> set = new HashSet<Integer>();
        List<Integer> item = new ArrayList<Integer>();
        while(true){
            for(int i=0;i<nums.length;i++){//往下递归的过程
                if(set.contains(i)) continue;
                stack.push(i);
                set.add(i);
                item.add(nums[i]);
                break;
            }
            if(item.size()==nums.length){
                result.add(new ArrayList<Integer>(item));
                item.remove(item.size()-1);
                set.remove(stack.pop());
                int j;
                for(j = nums.length;j>=nums.length;){//实现回溯过程
                    if(stack.empty()) return result;
                    j = stack.pop();
                    set.remove(j);
                    item.remove(item.size()-1);
                    for(j++;j<nums.length&&set.contains(j);j++);
                }
                stack.push(j);
                set.add(j);
                item.add(nums[j]);
            }
        }
    }
}
  • 从上可以看出,一般说来,用迭代的方法来实现递归,都要借用到栈来保存当前的数组下标,在合适的时候回溯时,要在这个下标的地方往下递归,所以这里使用到栈来保存下标,但是可以看到迭代方法比较复杂。

Solution3

  • 另一种类型的递归,更加trick一些
public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        permute3(nums,0,result);
        return result;
    }
    public void permute3(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;
        }
        for(int i=start;i<nums.length;i++){
            int temp = nums[start];
            nums[start] = nums[i];
            nums[i] = temp;
            permute3(nums,start+1,result);
            nums[i] = nums[start];
            nums[start] = temp;
        }
    }
}

Solution4

  • 这里实际可以用动态规划的方法来求解。基本思路如下:当数组为[1]时,则答案为[1];当数组为[1,2]时,则答案为[1,2]和[2,1];当数组为[1,2,3]时,则答案可以在[1,2]和[2,1]的基础上构成。即往这两个数组中的不同位置插入3即可。如此得到下面的解法
import java.util.List;
import java.util.ArrayList;
public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(nums.length==0) return result;
        List<Integer> temp = new ArrayList<Integer>();
        temp.add(nums[0]);
        result.add(temp);
        for(int i=1;i<nums.length;i++){
            int size = result.size();
            for(int j=0;j<size;j++){
                temp = result.get(j);   
                for(int k=0;k<=temp.size();k++){//这里便是各个位置插入的过程
                    ArrayList<Integer> temp1 = new ArrayList<Integer>(temp);
                    temp1.add(k,nums[i]);
                    result.add(temp1);
                }
            }
            while(size-->0) result.remove(0);
        }
        return result;
    }
}

Solution5

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值