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 }
測試結果以下所示:java