本题目在凌应标老师的《算法设计与分析》第八次作业中出现,可供参考。

题目描述:

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

要完成的函数:

void nextPermutation(vector<int>& nums)

说明:

1、这道题给定一个vector,里面装着各种数字,比如123这样子,要求按照字典序输出当前排列的下一种排列,比如123的下一种字典序排列就是132。

如果当前已经不存在更大的下一种排序,比如321,已经到达最大了,那么输出123,这种最小的字典序排列。

除此之外,只允许原地修改,使用额外常数级空间。

2、这道题挺有意思的,如果要求输出所有的排列情况,并且按照字典序排列,存储在vector中返回,你会怎么做?

笔者觉得也许可以参考leetcode-17-电话号码的字母组合这种思路来做。

回到当前这道题,我们写几个排列来看下情况,如下:

1234的下一个排列是1243,从后面找起,如果倒数第二个比倒数第一个小,那么交换两个的数值,结束。

1243的下一个排列是1324,从后面找起,倒数第二个不会比倒数第一个小,所以只能继续往前走,倒数第三个比倒数第二个小,所以我们只需要交换从倒数第三个开始的vector元素。

1324的下一个排列是1342,规则一样,从后面找起,倒数第二个比倒数第一个小,交换两个的数值,结束。

1342的下一个排列是1423,从后面找起,倒数第二个不会比倒数第一个小,所以只能继续往前走,倒数第三个比倒数第二个小,所以我们只需要交换从倒数第三个开始的vector元素。

……

1432的下一个排列是2134,从后面找起,发现只有第一位小于第二位,所以我们要交换整个vector中的元素。

通过上述举例,我们可以发现,如果前面一个的数值小于后面一个,那么我们就要交换从前面一个到vector最后面的所有元素。而如果不满足这个条件,那么继续往前走。

如果走到第一位了,发现还是不满足,那么说明当前排列已经是字典序最大的排列了,我们只需要两两交换一下,便可以变成字典序最小的排列。

那我们要怎样交换从前面一个到vector最后面的所有元素?

举个例子,2431的下一个排列,是3124。

我们往前走到第一位,才找到前一个元素2小于后一个元素4的情况,此时,我们继续从后面找起,找到大于前一个元素的第一个元素3,因为431这种排列,决定了从后面找起的第一个大于前一个元素的元素3,是大于前一个元素2的最小元素。

交换他们的数值,这时候变成3421。

接着从4开始,头跟尾两两不断交换,也就是我们最终要的结果,3124。

附上代码,如下:

    void nextPermutation(vector<int>& nums)
{
int s1=nums.size()-1,s2=s1-1,i;//s1表示最后一位,s2表示我们最开始从倒数第二位开始找起
while(s2>=0)//一直找,找到前一个元素小于后一个元素的这种情况
{
if(nums[s2]<nums[s2+1])
break;
s2--;
}
if(s2==-1)//如果全程没找着,s2已经是-1了,那么说明当前是字典序最大的排列
{
for(int i=0;i<=s1/2;i++)//头跟尾两两不断地交换
swap(nums[i],nums[s1-i]);
}
else//如果找着了,nums[s2]这时候要跟后面大于nums[s2]的最小元素交换数值
{
i=s1;
while(i>s2)//找到大于nums[s2]的最小元素
{
if(nums[i]>nums[s2])
break;
i--;
}
swap(nums[s2],nums[i]);//两两交换数值
for(i=s2+1;i<=(s1+s2+1)/2;i++)//从s2+1这个位置开始,头跟尾两两不断地交换
swap(nums[i],nums[s1+s2+1-i]);
}
}

这道题有意思就有意思在,你发现你要再往前找一位来交换的时候,比如2431,你必须找到2,2是第一个小于后面元素4的元素,这时候你会发现2后面的排列刚好是从大到小的排列,是一个降序排列。

因为是降序排列,所以省去我们很多功夫,比如找到大于2的最小元素,只需要从后面找起,第一个大于2的3就是了。

再比如交换完2和3这两个数值,我们得到了3421,接下来我们从4开始,后面的元素(包括4本身),还是一个降序排列,继续头跟尾两两交换就可以了。

笔者最开始还想得挺复杂,比如什么逐一比较,找到大于2的最小元素;什么4之后的元素通过冒泡排序来调整顺序。但都不需要。

上述代码实测8ms,beats 100.00% of cpp submissions。

leetcode-31-下一个排列的更多相关文章

  1. Java实现 LeetCode 31下一个排列

    31. 下一个排列 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许 ...

  2. LeetCode 31. 下一个排列 | Python

    31. 下一个排列 题目 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改, ...

  3. LeetCode 31. 下一个排列(Next Permutation)

    题目描述 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许使用额外常 ...

  4. leetcode 31下一个排列

    /** 验证一般情况(元素数目大于等于3)有几个情况分析:两个特殊情况: 6 5 4 3 2 1 完全反序,这种序列没有下一个排序,因此重新排序1 2 3 4 5 6 1 2 3 4 5 6 完全升序 ...

  5. LeetCode:下一个排列【31】

    LeetCode:下一个排列[31] 题目描述 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排 ...

  6. Leetcode题库——31.下一个排列

    @author: ZZQ @software: PyCharm @file: nextPermutation.py @time: 2018/11/12 15:32 要求: 实现获取下一个排列的函数,算 ...

  7. Leetcode题目31.下一个排列(中等)

    题目描述: 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许使用额外 ...

  8. 【LeetCode】下一个排列【找规律】

    实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许使用额外常数空间. ...

  9. 代码题(45)— 下一个排列、第k个排列

    1.31. 下一个排列 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只 ...

  10. [LeetCode] 31. Next Permutation 下一个排列

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

随机推荐

  1. Linux 下批量创建用户(shell 命令)

    第一种方法: 用shell批量创建用户,分为2中:1,批量创建的用户名无规律 :2.批量创建的用户名有规律首先,来说下批量创建的用户名无规律的shell:先把需要批量创建的用户名用一个文本文档列出来, ...

  2. Halcon中缩放Region或XLD的方法研究

    在Halcon中,Region和XLD之间可以彼此转换.但这种转换并不是“无损”的,XLD可以是不闭合的,但是Region一定是闭合的.因此,如果将不闭合的XLD转为Region,然后再转回XLD,那 ...

  3. android 的AlertDialog对话框

    private int selectedFruitIndex = 0;  private void showMsg2() {//  Dialog alertDialog = new AlertDial ...

  4. iOS密码输入框的实现

    [iOS密码输入框的实现] 就是一个UITextField,把属性 UITextField.secureTextEntry设置为Yes即可.此种UI效果为iOS默认效果.

  5. 使用electron-packager electron-builder electron-updater 打包vue项目,支持在线更新

    1.如何用electron-packager electron-builder打包vue项目,打包成桌面程序. 步骤一. 执行npm run build 打包你的vue项目. 打包成功后,生成dist ...

  6. iOS隐藏导航条1px的底部横线

    第二种方法:1)声明UIImageView变量,存储底部横线 @implementation MyViewController { UIImageView *navBarHairlineImageVi ...

  7. jmeter 正则表达式

    1.抓好请求,对着接口文档筛选好请求后,添加正则表达式 2.查看结果树,找到要提取的参数 3.书写正则 4.关联一下 5.直接跑一边就好,包成功,从数据库取的话,如果name:user,就直接参数化: ...

  8. Image 和byte[]之间的转换

    1.Image 转 byte[] public byte[] GetByteByImage(Image image) { byte[] bt = null; try { if (!image.Equa ...

  9. Hdu1429 胜利大逃亡(续) 2017-01-20 18:33 53人阅读 评论(0) 收藏

    胜利大逃亡(续) Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Subm ...

  10. (轉)Equal height boxes with CSS

    原文:http://www.456bereastreet.com/archive/200405/equal_height_boxes_with_css/ 下面是我翻译的内容,是根据我对文章的理解意译的 ...