31. 下一个排列
题目描述
一开始我读这个题目,我是真看不懂这个题目再讲什么,什么下个排序,后面看了下官方题解才知道这里的排序也就是字典序。
字典序
字典序(dictionary order),又称 字母序(alphabetical order),原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。
英文中的 字母表(Alphabet) 按照如下的顺序排列:
ABCDEFG HIJKLMN OPQRST UVWXYZ
abcdefg hijklmn opqrst uvwxyz
在字典中,单词是按照首字母在字母表中的顺序进行排列的,比如 alpha 在 beta 之前。而第一个字母相同时,会去比较两个单词的第二个字母在字母表中的顺序,比如 account 在 advanced 之前,以此类推。
示例分析
这里给出的nums = [1,2,3,4]
如果按照字典序将上面请况进行排序
-
1234
-
1243
-
1324
-
1342
-
1423
-
1432
-
…
-
4321
我们可以从上面的例子中看出来字典序最大的是4321,这个全部都是递减次序的。那么我们找到下一个排序呢?
比如我们吗在1243这个位置,我们想要找到下一个排序,首先我们想要让它变大我们就要把递减次序给变成递增的,因为字典序是从前面往后,所以我们要从后往前把第一个递减的位置(倒着看)给找到
这里我们找到的是2和4,分别定义下标为 i 和 j。如果这个时候你直接调换就会出问题 那就是 1423 这个虽然 大于 1243 但并不一定是下一个。我们要的是把这个2给换成一个大的数据,就要从后往前找第一个比2大的数据也就是3,然后把2个数字进行交换得到 1324 -
如果当前排列是1243,找它的下一个排列的方法是,从这个序列中从右至左找第一个左邻小于右邻的数
-
如果找不到,则所有排列求解完成,如果找得到则说明排列未完成
-
本例中将找到24,计4所在的位置为i,找到后不能直接将24位置互换,而又要从右到左到第一个比2大的数
-
本例找到的数是3,其位置计为j,将i与j所在元素交换1324
然后将i+1至最后一个元素从小到大排序得到1324,这就是1324的下一个排列。
总而言之,就是找到递减的位置(从后往前)然后从后面找到比他大的第一个数然后进行交换再把后面的剩余的数进行排序就可以得到。
因为最后是逆序只要反转下就能得到正序就排序好了
代码
class Solution {
public void nextPermutation(int[] nums) {
int n = nums.length;
// 特殊请况,一个数字不用排序
if (n == 1) {
return;
}
// 从后往前找到第一个递减的两个数字(相邻)
// 1 2 4 3
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = n - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums, i, j);
}
// 因为后面是逆序的所以反转就是正序正好是sort(从小到大)
reverse(nums, i + 1);
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
private void reverse(int[] nums, int start) {
int left = start, right = nums.length - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}