全排列问题

在解决全排列问题之前,先讲解一个它的子问题,输出给定数字比它大的下一个数字,为了方便,我们把输入和输出数字用数组表示

给出一组数,输出它的下一个排列

假设给定数组[1,2,3,5,4]  比它大的下一个数字是[1,2,4,3,5]

思想:

假设出入数组为arr

1.我们从后向前遍历,找到arr[i]>arr[i-1],并且返回i,如果没有找到返回0;

2.用index接收返回的下标,判断index是否等于0,如果等于0,返回null,否则在区间 arr.length-1 和 index 区间找出比arr[index-1]小的值,两者交换,并退出循环;

3.在对 index和arr.length-1组成的区间 进行逆序,

4.返回数组arr,数组arr表示当前数组的下一个排列

实现图如下:

实现代码如下:

     //找到下一个排列  
     public static int[] findNearestNumber(int[] arr){
        int index = returnIndex(arr);
        if(index == 0) return null;
        for(int i = arr.length-1;i>=index;i--){
            if(arr[index-1]<arr[i]){
                int tmp = arr[index-1];
                arr[index-1] = arr[i];
                arr[i] = tmp;
                break;
            }
        }
        reverseArr(arr,index,arr.length-1);
        return arr;

    }

    //逆序
    public static void reverseArr(int[] arr,int start,int end){
        while(start<=end){
            int tmp = arr[start];
            arr[start++] = arr[end];
            arr[end--] = tmp;
        }
    }
    //从后向前遍历找出arr[i]<arr[i-1]的下标i
    public static int returnIndex(int[] arr){
        for (int i = arr.length-1; i >0 ; i--) {
            if(arr[i]>arr[i-1]){
                return i;
            }
        }
        return 0;
    }

这就是求一个数组的下一个排列数组,是不是很简单?

下面这个全排列的例子该如何实现呢?

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

通过上面的例子,我们可以求出一个数组的比它大的下一个数组,那么我们要输出给定某数组的全部排列就很简单了,在解决此题之前,我们首先的判断该数组总共有多少排列组合,然后在进行操作,先对该数组按升序进行排序,也就是最小值a,我们可以求a的下一个排列b,紧接着我们可以求b的下一个排列c...直到该排列为空,我们就求出了该数组的全部排列组合。

代码如下:

public List<List<Integer>> permute(int[] nums) {
        Arrays.sort(nums);
        int length = nums.length;
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        int n = getN(length);
        for(int i = 0;i<n;i++){
            List<Integer> list1 = new ArrayList<Integer>();
//将原数组加入集合中
if(i == 0){ List<Integer> list2 = new ArrayList<Integer>(); for(int j:nums){ list2.add(j); } list.add(list2); }
       //求得nums下一个排列 nums
= findNearestNumber(nums);
        //如果返回数组为null表示已经排列完成,结束循环
if(nums == null) break;
//将数组元素加入集合中
for(int j:nums){ list1.add(j); }
   //将集合list1加入集合list中 list.add(list1); }
return list; } //获取总共的排列组合数 public static int getN(int length){ if(length == 1){ return length; } return length*getN(length-1); } //排列 public static int[] findNearestNumber(int[] arr){ int index = returnIndex(arr); if(index == 0) return null; for(int i = arr.length-1;i>=index;i--){ if(arr[index-1]<arr[i]){ int tmp = arr[index-1]; arr[index-1] = arr[i]; arr[i] = tmp; break; } } reverseArr(arr,index,arr.length-1); return arr; } //逆序 public static void reverseArr(int[] arr,int start,int end){ while(start<=end){ int tmp = arr[start]; arr[start++] = arr[end]; arr[end--] = tmp; } } //从后向前遍历找出arr[i]<arr[i-1]的下标i public static int returnIndex(int[] arr){ for (int i = arr.length-1; i >0 ; i--) { if(arr[i]>arr[i-1]){ return i; } } return 0; }

如果给定的数组有重复的数字,那么我们该如何解决呢?

其实上面的代码也适用于数组有重复数字,这就是采用非递归的好处。

下面是采用递归实现代码:

这个代码实现给定的数组中没有重复数字的

   //递归实现 调用时n是0
    public static void printSort(int[] num, int n) {
        if(n >= num.length-1){
            System.out.println(Arrays.toString(num));
        }
        else{
            for(int i = n;i < num.length;i++) {
                    swap(num,i,n);
                    printSort(num,n+1);
                    swap(num,i,n);
 
            }
        }
    }
   //交换指定下标元素
    public static void swap(int[] num, int i, int n) {
        int flag = num[i];
        num[i] = num[n];
        num[n] = flag;
    }
 

如果有重复的元素,用递归该如何实现,其实很简单,我们只要让第一次出现该数作为开头

代码如下:

    //调用时n是0
    public static void printSort(int[] num, int n) {
        List<Integer> list = new ArrayList<Integer>();
        if(n >= num.length-1){
            System.out.println(Arrays.toString(num));
        }
        else{
            for(int i = n;i < num.length;i++) {
                //筛选重复的数
                if(!list.contains(num[i])){
                    list.add(num[i]);
                    swap(num,i,n);
                    printSort(num,n+1);
                    swap(num,i,n);
                 }
            }
        }
    }
 
    public static void swap(int[] num, int i, int n) {
        int flag = num[i];
        num[i] = num[n];
        num[n] = flag;
    }
 

  

原文地址:https://www.cnblogs.com/du001011/p/10833307.html