刚入职不久,打算分门别类的刷一下LeetCode,于是首先从Array类的题目开始。今天做到一个题目,题号是31,原文题目如下:
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
刚开始连题目也没读懂,后来百度了一下,得知题目大意是:
写一个方法,实现输入排列的增大,即把输入排列增大到按字典序的下一个排列,若输入排列已经是最后一个排列,则将其升序排序。此外,题目要求不能分配额
外的空间,并给出了几个示例。
题中的permutation指的就是数学中的排列,举个栗子:
数字1,2,3的全排列依次是
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
结合题意,个人的理解是,“下一个排列”指的是在输入序列的全排列中,当前输入排列的下一个排列,也可将每一个排列看成一个数字,如1 2 3看成123,那么它的
下一个排列1 3 2就是132,132>123。
题目虽然弄懂了,但是想了一会也没有什么好的思路,看到nomasp博客上的思路,觉得很棒,于是想记录下来。
解题思路分析如下:
假设输入排列为 6 5 4 8 7 5 1
那么如何得到这个排列的下一个更大的排列呢,我们可以从排列的尾部开始看,如果交换1和5,得到的新排列是变小的,同样,任意交换7 5 1三个数字也不可能得
到比原排列更大的排列,更进一步,8 7 5 1的任意一个新排列也不会使原排列增大,那么我们可以发现,输入排列中的递减子排列对排列的增大是无用的。因此,如果
要使输入排列增大,我们必须找到增大的那个位置,即与输入排列从尾部开始扫描得到的递减子排列相邻的那个位置。这个位置就是与 8 7 5 1相邻的4,另外在8 7 5 1
四个数中比4大的数是5 7 8,因此4需要与5交换位置,即与比4大的所有数中的最小者交换位置,交换后得到:6 5 5 8 7 4 1,然后再对8 7 4 1做一个递增排序,就得到
了题目要求的排列。
Java实现的代码如下:
public static int[] nextPermutation(int[] nums)
{
int n = nums.length;
if(nums ==null || n == 1)
return nums;
int index = n-1;
while(index >0&&nums[index] <= nums[index-1])
{
--index;
}
if(index == 0)
{
Arrays.sort(nums);
return nums;
}
int big = Integer.MAX_VALUE;
int bigindex = 0;
for(int i = n-1;i >= index-1;--i)
{
if(nums[i] > nums[index-1])
{
if(nums[i] < big)
{
big = nums[i];
bigindex = i;
}
}
}
int temp;
temp = nums[index-1];
nums[index-1] = nums[bigindex];
nums[bigindex] = temp;
Arrays.sort(nums, index, n);//排序时包括index,不包括n
return nums;
}