此问题描述如下:
给定一个数组,首先从后向前找出最长的递减序列的前一个元素,比如数组{1, 5, 8, 4, 7, 6, 5, 3, 1}中,从后向前最长递减序列是{ 7, 6, 5, 3, 1},这个序列的前一个元素就是4,然后再递减序列中找到最后一个比这个数(4)大的数字(就是5),然后将5与4交换,得到新的数组{1, 5, 8, 5, 7, 6, 4, 3, 1},然后将交换过后的递减序列进行翻转,最后得到的结果就是{1 5 8 5 1 3 4 6 7 }。如果数组单调递减的数组,比如说是{4,3,2,1},则直接翻转就可以得到最终的结果{1,2,3,4}。
注意交换的过程中不能使用额外的空间
如图表示就是:
代码实现:
/**
* @version 2017/7/21.21:33
*/
public class NextPermutation {
public static void main(String[] args) {
int[] nums = {1, 5, 8, 4, 7, 6, 5, 3, 1};
new NextPermutation().nextPermutation(nums);
for (int num : nums) {
System.out.print(num + " ");
}
}
public void nextPermutation(int[] nums) {
if (nums == null || nums.length == 1) {
return;
}
int decreasingElementIndex = getDecreasingElement(nums);
if (decreasingElementIndex == -1) {
reverse(nums, 0);
return;
}
swap(nums, decreasingElementIndex, getLastLargeElement(nums, decreasingElementIndex));
reverse(nums, decreasingElementIndex + 1);
}
//获取比第一个数组中从后向前递减的数大的数
public int getLastLargeElement(int[] nums, int start) {
int num = nums[start];
int index = start + 1;
while (index < nums.length) {
if (nums[index] > num) {
start++;
}
index++;
}
return start;
}
//从数组的 某一位置开始反转数组
public void reverse(int[] nums, int starIndex) {
int endIndex = nums.length - 1;
while (starIndex < endIndex) {
swap(nums, starIndex, endIndex);
starIndex++;
endIndex--;
}
}
//从数组的后向前获取第一个递减的数字的下标,比如{1,4,3,2},此时要求的 结果就是0
public int getDecreasingElement(int[] nums) {
int lenght = nums.length - 1;
while (lenght >= 1) {
if (nums[lenght] > nums[lenght - 1]) {
return lenght - 1;
}
lenght--;
}
return -1;
}
//交换两个数
public void swap(int[] nums, int i, int j) {
if (i != j) {
nums[i] = nums[i] ^ nums[j];
nums[j] = nums[i] ^ nums[j];
nums[i] = nums[i] ^ nums[j];
}
}
}