leetcode_31.下一个排列
·
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
解析:本题实现上不难,主要在于想明白逻辑。
什么是字典序?就是类似于字典上的目录排序,就比如123的字典序排列出来便是:
123、132、213、231、312、321
如果不了解什么是字典序那么肯定不知道怎么做
对于一个序列,我们需要找到它的尾部最长递减序列,例如序列1,2,3,4,5,6,7,6,5,4,3,2,1
它的这个序列便是7,6,5,4,3,2,1。这一部分在字典序中已经是最大的,因此在下一个排列中,它必然会重新排列为最小的顺序,而对于这个递减序列,便是将它倒转。
此时的序列变为1,2,3,4,5,6,1,2,3,4,5,6,7
对于原序列,最长递减序列之前的数字为6,如果去掉它之前的部分,6,7,6,5,4,3,2,1.
6之后的子序列已经是最大的排列,因此下一个序列必然会交换这个子序列前面的数字6,以构筑一个比原序列大,并在所有可能序列中最小的下一个排序。
为了让这个序列更大,必须将6变为一个更大的数字,所以从6之后的子序列,找到一个比6大且相对最小的数字,对于本例为7,将这两个数字交换,便得到了下一个字典序
1,2,3,4,5,7,1,2,3,4,5,6,6
class Solution {
public:
void nextPermutation(vector<int>& nums) {
if(nums.size()<2) return;
//寻找数组末尾的最长递减序列
int i;
for(i=nums.size()-1;i>0&&nums[i-1]>=nums[i];--i);
//将该递减序列倒置
//手写版
/*int l=0+i;
int r=nums.size()-1;
while(l<r){
int tmp = nums[l];
nums[l] = nums[r];
nums[r] = tmp;
++l,--r;
}*/
//库函数版
reverse(nums.begin()+i,nums.end());
//如果i为0,则代表整个数组都是递减的,即目前的数组已经是最大的字典序
//经过倒转后已经变成最小排列,所以不需要这一步骤
//手写版
/*if(i--!=0){
int j = i;
//寻找比倒转序列前一个数字大的下一个数字
while(nums[i]>=nums[j]) ++j;
//将它们交换
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}*/
//库函数版
if(i--!=0){
auto it = upper_bound(nums.begin() + i, nums.end(), nums[i]);
swap(nums[i], *it);
}
//其实整个功能都可以用自带的库函数一行解决...但毕竟是算法题
//next_permutation(nums.begin(),nums.end());
}
};
更多推荐



所有评论(0)