寻找全排列的下一个数(字典序算法实现)
Posted zldmy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了寻找全排列的下一个数(字典序算法实现)相关的知识,希望对你有一定的参考价值。
给出一个正整数,找出这个正整数所有数字全排列的下一个数。通俗的说就是在一个整数所包含数字的全部组合中,找到一个大于且仅大于原数的新整数。举例:
- 如果输入:12345,则返回12354
- 如果输入:12354,则返回12435
- 如果输入:12435,则返回12453
思路:
字典序算法:
- 从后向前查看逆序区,找到逆序区域的前一位,作为数字置换的边界;
- 逆序区是指:数字大小(从左到右)排序一定会是从大到小。
- 所以从右往左找,第一个右边值大于左边值的位置,那么右边这个位置就是逆序区的起始点。
- 从右向左,从逆序区中找到大于【逆序区域起始点的前一位A】的最小的数字B,将A,B交换位置
- 因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从右向左找,第一个大于A的就一定也是逆序域中大于A的最小数字。
- 所以,从右向左遍历,找到第一个大于A的数字,就可以直接交换位置,退出循序。
- 把原来的逆序区域转为顺序状态;
- 同样的,因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从逆序区的两端,头尾值两两交换即可
举例: 1736542,逆序区域:6542,那么逆序区的起始点就是6,然后将3和4交换位置,变为:1746532,将逆序区域转为顺序状态:1742356。
代码实现:
1 package blogSrc; 2 3 import java.util.Arrays; 4 5 /** 6 * 寻找全排列的下一个数 7 * 给出一个正整数,找出这个正整数所有数字全排列的下一个数。通俗的说就是在一个整数所包含数字的全部组合中,找到一个大于且仅大于原数的新整数。举例: 8 * 如果输入:12345,则返回12354 9 * 如果输入:12354,则返回12435 10 * 如果输入:12435,则返回12453 11 * 12 * 思路: 13 * 从后向前查看逆序区(数字从大到小排序),找到逆序区域的前一位,作为数字置换的边界; 14 * 让逆序区域的前一位和逆序区域中大于它的最小的数字交换位置; 15 * 把原来的逆序区域转为顺序状态; 16 * 举例: 12354,逆序区域:54,那么数字置换的边界就是3,将3和4交换位置,变为:12453,将逆序区域转为顺序状态:12435。 17 */ 18 19 public class FindNearestNumber 20 21 public static void main(String[] args) 22 int[] numArr = 1,7,3,6,5,4,2; 23 int[] copyArr = Arrays.copyOf(numArr,numArr.length); 24 int[] result = new FindNearestNumber().findNearestNumber(copyArr); 25 System.out.println("原始的数组:" + Arrays.toString(numArr)); 26 System.out.println("处理后数组:" +Arrays.toString(result)); 27 28 29 public int[] findNearestNumber(int[] numArr) 30 int borderIndex = getReverseBorderIndex(numArr); 31 //如果borderIndex=0,说明这个那个数组已经逆序,无法得到更大的相同数字组成的整数 32 if(borderIndex == 0) 33 return new int[0]; 34 35 int[] newNumArr = exchangePosition(numArr,borderIndex); 36 int[] result = changeReverse(newNumArr,borderIndex); 37 return result; 38 39 40 41 /** 42 * 从后向前,找到逆序区域边界点。 43 * 逆序区是指:数字大小(从左到右)排序一定会是从大到小。 44 * 所以从右往左找,第一个右边值大于左边值的位置,那么右边这个位置就是逆序区的起始点。 45 * @param numArr 46 * @return 47 */ 48 public int getReverseBorderIndex(int[] numArr) 49 int index = 0; 50 for (int i=numArr.length-1; i>0; i--) 51 if (numArr[i] > numArr[i-1]) 52 return i; 53 54 55 return index; 56 57 58 /** 59 * 从右向左,从逆序区中找到大于【逆序区域起始点的前一位A】的最小的数字B,将A,B交换位置。 60 * 因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从右向左找,第一个大于A的就一定也是逆序域中大于A的最小数字。 61 * 所以,从右向左遍历,找到第一个大于A的数字,就可以直接交换位置,退出循序。 62 * @param numArr 63 * @return 64 */ 65 public int[] exchangePosition(int[] numArr, int borderIndex) 66 int borderBeforeNum = numArr[borderIndex - 1]; 67 for (int i = numArr.length - 1; i > 0; i--) 68 if (numArr[i] > borderBeforeNum) 69 numArr[borderIndex - 1] = numArr[i]; 70 numArr[i] = borderBeforeNum; 71 break; 72 73 74 return numArr; 75 76 77 78 /** 79 * 把原来的逆序区域转为顺序状态. 80 * 同样的,因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从逆序区的两端头尾两两交换即可 81 * @param numArr 82 * @param borderIndex 83 * @return 84 */ 85 public int[] changeReverse(int[] numArr, int borderIndex) 86 for (int i = borderIndex, j = numArr.length - 1; i < j; i++, j--) 87 int temp = numArr[i]; 88 numArr[i] = numArr[j]; 89 numArr[j] = temp; 90 91 return numArr; 92 93 94
结果:
原始的数组:[1, 7, 3, 6, 5, 4, 2]
处理后数组:[1, 7, 4, 2, 3, 5, 6]
以上是关于寻找全排列的下一个数(字典序算法实现)的主要内容,如果未能解决你的问题,请参考以下文章