leetcode 46. Permutations(递归和字典序排序)

题目描述:

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

Example:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

思路1:

https://blog.csdn.net/orangefly0214/article/details/84558422和字符串排列的思路是一样的,这里,我们仍然采用递归的方法。固定住第一个字符,求剩余部分的全排列。

step1:把数组分为两部分,一部分是数组的第一个元素,另一部分是第一个元素以后的所有元素(有阴影背景的区域)。

step2:接下来求阴影部分数字的排列,拿第一个字符和后面的字符逐个交换。

参考下面这幅图:

 

实现1(递归):

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ret=new ArrayList<>();
		if(nums==null||nums.length==0){
			return ret;
		}
		fun(nums,0,ret);
		return ret;
    }
    private void fun(int[] nums, int i, List<List<Integer>> ret) {
		if(i==nums.length-1){
			if(!ret.contains(nums)){
				ArrayList<Integer> sub=new ArrayList<>();
				for(Integer ele:nums){
					sub.add(ele);
				}
				ret.add(sub);
				return;
			}
		}else{
			for(int j=i;j<nums.length;j++){
				swap(nums,i,j);
				fun(nums,i+1,ret);
				swap(nums,i,j);
			}
		}
		
	}
    private void swap(int[] nums, int i, int j) {
		int temp=nums[i];
		nums[i]=nums[j];
		nums[j]=temp;		
	}
}

实现2:字典序排序

字典序排序的方法:

1.从该序列的最右端开始向左找出第一个比与自己相邻的右边数小的数,记其下标为j,即j = max{i|Pi<Pi+1}.

2.找出Pj右边比Pj大的最小数Pk.

3.交换Pj,Pk.此时序列变为 P’: P1 P2 P3...Pj-1 Pk Pj+1...Pk-1 Pj Pk+1...Pn

 4.将Pj+1...Pn 倒转,即得到此序列的后一个序列 P”: P1 P2 P3...Pj-1 Pn...Pk+1 Pj Pk-1...Pj+1④

总结概括为以下四步:

①从右往左,找到第一个比后一个数小的数,找到的这个数的下标记为index。

②从右往左,找到第一个比找到数大的数,下标记为j.

③交换index和j.

④对index+1以后的数进行一个整体的reverse。

循环退出的条件:j==0时,返回最终的结果集。

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ret=new ArrayList<>();
        if(nums==null||nums.length==0){
            return ret;
        }
       if(nums.length==1){
			ArrayList<Integer> temp=new ArrayList<>();
			temp.add(nums[0]);
		    ret.add(temp);
		    return ret;
		 }
        Arrays.sort(nums);
        while(true){
            ArrayList<Integer> sub=new ArrayList<Integer>();
            for(Integer ele:nums){
                sub.add(ele);
            }
            ret.add(new ArrayList<>(sub));
            int j;
            int index=0;
            for(j=nums.length-2;j>=0;j--){
                if(nums[j]<nums[j+1]){
                    index=j;
                    break;
                }else if(j==0){
                    return ret;
                }
            }
            for(j=nums.length-1;j>=0;j--){
                if(nums[j]>nums[index]){
                    break;
                }
            }
            swap(nums,index,j);
            reverse(nums,index+1,nums.length-1);                        
        }
    }
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
    private void reverse(int[] nums,int i,int j){
        while(i<j){
            swap(nums,i,j);
            i++;
            j--;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值