java实现字典序算法(C++中的nextPermutation函数的java实现)

  1 //问题:给定一个正整数,求该数的下一个字典序数,即下一个全排列数,即最小的大于该数的排列数
  2 //如123 132 213 231 312 321 是一个全排列序列,那么123的下一个字典序数就是132
  3 
  4     /*
  5     该题采用字典序算法,步骤如下:
  6       1.从后向前查看逆序区域,找到逆序区域的前一位.(所谓逆序区域即倒排的区域,如12354的逆序区域是最后两位,即从后往前递增的区域)
  7       2.把逆序区域的前一位和逆序区域中刚好大于它的的数字交换位置.(如13542,逆序区域中刚好大于3的是4,所以交换后得到14532)
  8       3.把原来的逆序区域中的数转为顺序(因为交换后的逆序区域中的数依然是倒序,所以只要用两个指针指向逆序区域的头尾,两两交换再移动指针再交换...就转成顺序了)
  9 
 10      第一步之所以这样做是因为,如1,2,3,4,5这5个数组成的全排列中,12345是全排列中最小的数,因为其是顺排,54321是全排列中最大的数,因为其是倒排,那么如12354,
 11      其逆序区域是最后两位,即最后两位已经没法再大了,所以就要找到倒数第三位,将逆序区域中刚好比3大的数4和倒数第三位的数字3互换,得到12453,(之所以要找刚好大于的是因为我们要求
 12      的是下一个全排列数),然后再将原来的逆序区域中的数按顺序排列,得到12435,因为原来的逆序区域按顺序排列后得到的才是下一个字典序数.
 13     * */
 14 
 15 import java.util.Arrays;
 16 import java.util.Scanner;
 17 
 18 /**
 19  * c++中的nextPermutation函数的java实现
 20  */
 21 public class NextPermutation {
 22     //将输入的非负数转成int数组
 23     private static int[] intToIntArray(int number) {
 24         if (number < 0) {
 25             throw new RuntimeException("输入的数不能为负数");
 26         }
 27         String str = String.valueOf(number);
 28         int[] numbers = new int[str.length()];
 29         for (int i = 0; i < str.length(); i++) {
 30             char c = str.charAt(i);
 31             numbers[i] = Integer.parseInt(c + "");
 32         }
 33         return numbers;
 34     }
 35 
 36     //获取逆序区域的起始下标
 37     private static int getRevRegionHeadIndex(int[] numbers) {
 38         for (int i = numbers.length - 1; i > 0; i--) {
 39             if (numbers[i] > numbers[i - 1]) {
 40                 return i;
 41             }
 42         }
 43         return 0;
 44     }
 45 
 46     //将逆序区域的前一位数字和逆序区域中刚好大于它的数字交换
 47     private static int[] exchange(int[] numbers, int index) {
 48         for (int i = numbers.length - 1; i > index - 1; i--) {
 49             if (numbers[index - 1] < numbers[i]) {
 50                 swap(numbers, index - 1, i);
 51                 return numbers;
 52             }
 53         }
 54         return numbers;
 55     }
 56 
 57     private static void swap(int[] numbers, int i, int j) {
 58         int temp = numbers[i];
 59         numbers[i] = numbers[j];
 60         numbers[j] = temp;
 61     }
 62 
 63     //将交换后的逆序区域中的数按顺序排列
 64     private static int[] reverse(int[] exchange, int index) {
 65         for (int i = index, j = exchange.length - 1; i < j; i++, j--) {
 66             swap(exchange, i, j);
 67         }
 68         return exchange;
 69     }
 70 
 71     private static int intArrayToInt(int[] reverse) {
 72         StringBuilder sb = new StringBuilder();
 73         for (int i = 0; i < reverse.length; i++) {
 74             sb.append(reverse[i]);
 75         }
 76         String str = sb.toString();
 77         int nextPermutation = Integer.parseInt(str);
 78         return nextPermutation;
 79     }
 80 
 81     //返回一个非负整数的下一个全排列数,如果已经是最大了,返回它本身.
 82     public static int getNextPermutation(int number) {
 83         int[] numbers = intToIntArray(number);
 84         int revRegionHeadIndex = getRevRegionHeadIndex(numbers);
 85         if (revRegionHeadIndex == 0) {
 86             return number;
 87         }
 88         int[] exchange = exchange(numbers, revRegionHeadIndex);
 89         int[] reverse = reverse(exchange, revRegionHeadIndex);
 90         int nextPermutation = intArrayToInt(reverse);
 91         return nextPermutation;
 92     }
 93 
 94     public static void main(String[] args) {
 95         //测试
 96         try {
 97             System.out.println(NextPermutation.getNextPermutation(0));
 98             System.out.println(NextPermutation.getNextPermutation(12453));
 99             System.out.println(NextPermutation.getNextPermutation(12345));
100             System.out.println(NextPermutation.getNextPermutation(54321));
101             System.out.println(NextPermutation.getNextPermutation(12333));
102             System.out.println(NextPermutation.getNextPermutation(-12345));
103         } catch (Exception e) {
104             System.out.println("输入的数必须是非负整数!");
105         }
106 
107          /* //使用Scanner进行测试
108         Scanner scan = new Scanner(System.in);
109         // 从键盘接收数据
110         System.out.println("请输入一个非负整数:");
111         // 判断是否还有输入
112         while (scan.hasNext()) {
113             String str = scan.next();
114             System.out.println("您输入的数是: " + str);
115             int nextPermutation = 0;
116             try {
117                 nextPermutation = NextPermutation.getNextPermutation(Integer.parseInt(str));
118             } catch (NumberFormatException e) {
119                 System.out.println("输入的数必须是非负整数!");
120                 System.out.println();
121                 System.out.println("请输入一个非负整数:");
122                 continue;
123             }
124             System.out.println("该数的下一个全排列数为:" + nextPermutation);
125             System.out.println();
126             System.out.println("请输入一个非负整数:");
127         }
128         scan.close();    */
129     }
130 }

 

测试结果如下所示:

 

posted @ 2018-04-13 15:54  红茶不知道  阅读(496)  评论(0)    收藏  举报