实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
离散数学及其应用书中有一个next字典序最大排列的算法伪代码:
解答版本1:
1、
class Solution {
public void nextPermutation(int[] nums) {
//从尾至头遍历,遇见第一个逆序的i,i+1;
boolean noRev = true;
int i=nums.length-2 ;
for(; i>=0 ; i--){
if(nums[i] < nums[i+1]){
//存在逆序i,i+1
noRev = false;
break;
}
}
if(!noRev){
//将i位置替换为(i,size-1]内大于nums[i]的下一个字典序排列,剩余位置字典序排列,
Arrays.sort(nums,i+1,nums.length);
for(int j=nums.length-2 ; j>=i ; j--){
if(nums[j] <=nums[i]){
int tmp = nums[i];
nums[i] = nums[j+1];
nums[j+1] =tmp;
Arrays.sort(nums,j+1,nums.length);
break;
}
}
}else{
//如不存在逆序,则全局字典序排列
Arrays.sort(nums);
}
}
}
改进版本1:在步骤将i位置替换为(i,size-1]内大于nums[i]的下一个字典序排列时:
因为排列为【nums[i] ,大于nums[i] ,待寻找区间】 for循环手动寻找index =待寻找区间内 大于nums[i]的最小数,swap(i,index),然后sort(i+1,end)
class Solution {
public void nextPermutation(int[] nums) {
//从尾至头遍历,遇见第一个逆序的i,i+1;将i位置替换为(i,size-1]内大于nums[i]的下一个字典序排列,剩余位置字典序排列,如不存在逆序,则全局字典序排列
boolean noRev = true;
int i=nums.length-2 ;
for(; i>=0 ; i--){
if(nums[i] < nums[i+1]){
//存在逆序i,i+1
noRev = false;
break;
}
}
if(!noRev){
// Arrays.sort(nums,i+1,nums.length);
// for(int j=nums.length-2 ; j>=i ; j--){
// if(nums[j] <=nums[i]){
// int tmp = nums[i];
// nums[i] = nums[j+1];
// nums[j+1] =tmp;
// Arrays.sort(nums,j+1,nums.length);
// break;
// }
// }
int right = nums[i+1];
int index =i;
for(int j=i+1 ; j<nums.length ; j++){
//大于nums[i]中最小的索引
if(nums[j]>nums[i]){
if(nums[j]<=right){
index = j;
right=nums[j];
}
}
}
//swap
int tmp =nums[i];
nums[i] =nums[index];
nums[index] =tmp;
Arrays.sort(nums,i+1,nums.length);
}else{
Arrays.sort(nums);
}
}
}