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 and use only constant 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
本题即为字典序算法。主要分为三步:
class Solution {
public void nextPermutation(int[] nums) {
//从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界
int i = nums.length-1;
while(i>0 && nums[i] <= nums[i-1]) {
i--;
}
//把逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置
if(i>0) {
int j = nums.length-1;
while(j>0 && nums[j] <= nums[i-1]) {
j--;
}
swap(nums, i-1, j);
}
//把原来的逆序区域转为顺序
reserve(nums, i);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private void reserve(int[] nums, int i) {
int j =nums.length-1;
while(i < j) {
swap(nums, i, j);
i++;
j--;
}
}
}
字典序,是基于字母顺序排列的单词按字母顺序排列的方法。 这种泛化主要在于定义有序完全有序集合(通常称为字母表)的元素的序列(通常称为计算机科学中的单词)的总顺序。
对于数字1、2、3…n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。
字典序算法用来解决这样一个问题:给定其中一种排列,求基于字典序的下一种排列。
比如给定一种排列为 abc,则其基于字典序的下一种排列为 acb。
要求下一种排列既要比原排列大,又不能有第三种排列位于他俩之间。即下一种排列为大于原排列的最小排列。
以输入为 358764 为例,字典序算法的步骤为:
3 5 8 7 6 4
↑ ↑
i-1 j
(交换 i-1,j 位置)
3 6 8 7 5 4
↑
i
(将 i 及其后面的数变为顺序排列)
3 6 4 5 7 8
注意:
总结算法思路为:
1. 从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界
2. 把逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置
3. 把原来的逆序区域转为顺序
时间复杂度:O(n) + O(n) + O(n) = O(n),在最坏的情况下,只需要对整个数组进行两次扫描
空间复杂度:O(1),没有使用额外的空间,原地替换足以做到