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 }
测试结果如下所示:


浙公网安备 33010602011771号