zoukankan      html  css  js  c++  java
  • 全排列问题

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

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

    假设给定数组[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;
        }
     
    

      

  • 相关阅读:
    Photoshop CC 与前端那些事
    gulp入門指南
    谈谈css左右等高的几个方法
    angularjs给Model添加拦截过滤器,路由增加限制,实现用户登录状态判断
    前端自动化工具
    React Router
    Sublime Text 3 常用插件安装
    c++ primer学习指导(13)--1.6书店程序
    c++ primer学习指导(12)--1.5.2初识成员函数
    c++ primer学习指导(11)--1.5.1Sales_item类
  • 原文地址:https://www.cnblogs.com/du001011/p/10833307.html
Copyright © 2011-2022 走看看