乘风破浪:LeetCode真题_031_Next Permutation
乘风破浪:LeetCode真题_031_Next Permutation
一、前言
这是一道经典的题目,我们实在想不出最好的方法,只能按照已有的方法来解决,同时我们也应该思考一下为什么要这样做?是怎么想到的?这比我们记住步骤更加的有用。
二、Next Permutation
2.1 问题

2.2 分析与解决
排列(Arrangement),简单讲是从N个不同元素中取出M个,按照一定顺序排成一列,通常用A(M,N)表示。当M=N时,称为全排列(Permutation)。从数学角度讲,全排列的个数A(N,N)=(N)*(N-1)*...*2*1=N!,但从编程角度,如何获取所有排列?那么就必须按照某种顺序逐个获得下一个排列,通常按照升序顺序(字典序)获得下一个排列。
例如对于一个集合A={1,2,3,},首先获取全排列a1: 1,2,3,;然后获取下一个排列a2: 1,3,2,;按此顺序,A的全排列如下:
a1: 1,2,3; a2: 1,3,2; a3: 2,1,3; a4: 2,3,1; a5: 3,1,2; a6: 3,2,1; 共6种。
对于给定的任意一种全排列,如果能求出下一个全排列的情况,那么求得所有全排列情况就容易了。好在STL中的algorithm已经给出了一种健壮、高效的方法,下面进行介绍。
/**
* current: 3 7 6 2 5 4 3 1 .
* | | | |
* find i----+ j k +----end
* swap i and k :
* 3 7 6 3 5 4 2 1 .
* | | | |
* i----+ j k +----end
* reverse j to end :
* 3 7 6 3 1 2 4 5 .
* | | | |
* find i----+ j k +----end
* */
具体方法为:
a)从后向前查找第一个相邻元素对(i,j),并且满足A[i] < A[j]。易知,此时从j到end必然是降序。可以用反证法证明,请自行证明。
b)在[j,end)中寻找一个最小的k使其满足A[i]<A[k]。由于[j,end)是降序的,所以必然存在一个k满足上面条件;并且可以从后向前查找第一个满足A[i]<A[k]关系的k,此时的k必是待找的k。
c)将i与k交换。
此时,i处变成比i大的最小元素,因为下一个全排列必须是与当前排列按照升序排序相邻的排列,故选择最小的元素替代i。易知,交换后的[j,end)仍然满足降序排序。因为在(k,end)中必然小于i,在[j,k)中必然大于k,并且大于i。
d)逆置[j,end)
由于此时[j,end)是降序的,故将其逆置。最终获得下一全排序。
e) 结束
如果在步骤a)找不到符合的相邻元素对,即此时i=begin,则说明当前[begin,end)为一个降序顺序,即无下一个全排列,STL的方法是将其逆置成升序。
通过上面的描述,我们可以进行一次全排列的算法,就会发现真的非常的有用,那么到底是怎么相处这种方法呢?我想其中的有一点非常重要,那就是每次都要从最右边向左边找到两个相邻的元素,使得满足小于关系。然后将小于关系左边的数字与右边第一个大于左边的数字交换顺序,这样之后再将右边的序列按照从小到大顺序来排列,这样做的好处是使得算法能继续运行下去,最妙的是,将更大的数字交换到左边,随着循环顺序的加深肯定左边的数字会越来越大,最终直至变成从大到小顺序来排列,这样就达到了目的。
public class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i + 1] <= nums[i]) {
i--;
}
if (i >= 0) {
int j = nums.length - 1;
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 1);
}
private void reverse(int[] nums, int start) {
int i = start, j = nums.length - 1;
while (i < j) {
swap(nums, i, j);
i++;
j--;
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
三、总结
遇到有些问题,是大家共同的认识并且经过长期探索得到的,如果我们使用传统的方法可能需要花费非常多的时间,因此,我们平时要多做题,从而懂得更多。
乘风破浪:LeetCode真题_031_Next Permutation的更多相关文章
- 乘风破浪:LeetCode真题_041_First Missing Positive
乘风破浪:LeetCode真题_041_First Missing Positive 一.前言 这次的题目之所以说是难,其实还是在于对于某些空间和时间的限制. 二.First Missing Posi ...
- 乘风破浪:LeetCode真题_040_Combination Sum II
乘风破浪:LeetCode真题_040_Combination Sum II 一.前言 这次和上次的区别是元素不能重复使用了,这也简单,每一次去掉使用过的元素即可. 二.Combination Sum ...
- 乘风破浪:LeetCode真题_039_Combination Sum
乘风破浪:LeetCode真题_039_Combination Sum 一.前言 这一道题又是集合上面的问题,可以重复使用数字,来求得几个数之和等于目标. 二.Combination Sum ...
- 乘风破浪:LeetCode真题_038_Count and Say
乘风破浪:LeetCode真题_038_Count and Say 一.前言 这一道题目,很类似于小学的问题,但是如果硬是要将输入和结果产生数值上的联系就会产生混乱了,因此我们要打破思维定势. ...
- 乘风破浪:LeetCode真题_037_Sudoku Solver
乘风破浪:LeetCode真题_037_Sudoku Solver 一.前言 这次我们对于上次的模型做一个扩展并求解. 二.Sudoku Solver 2.1 问题 2.2 分析与解决 这道题 ...
- 乘风破浪:LeetCode真题_036_Valid Sudoku
乘风破浪:LeetCode真题_036_Valid Sudoku 一.前言 有的时候对于一些基础知识的掌握,对我们是至关重要的,比如ASCII重要字符的表示,比如一些基本类型的长度. 二.Valid ...
- 乘风破浪:LeetCode真题_035_Search Insert Position
乘风破浪:LeetCode真题_035_Search Insert Position 一.前言 这次的问题比较简单,也没有限制时间复杂度,但是要注意一些细节上的问题. 二.Search Insert ...
- 乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array
乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array 一.前言 这次我们还是要改造二分搜索,但是想法却 ...
- 乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array
乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array 一.前言 将传统的问题进行一些稍微的变形,这个时候我们可能无所适从了,因此还是实践出真知, ...
随机推荐
- 解决:git使用git push 命令跳出remote: Permission to A denied to B的问题
开始git上传项目,不料,在git push这一步骤发生了错误? remote: Permission to qwe2193066947/firstRepository.git denied to m ...
- 百度前端技术学院task35源代码——听指令的小方块3
任务描述 如图,命令输入框由input变为textarea,可以允许输入多条指令,每一行一条 textarea左侧有一列可以显示当前行数的列(代码行数列),列数保持和textarea中一致 当text ...
- Quart2D setNeedsDisplay
#import "myview.h" @interface myview () @property(nonatomic,assign) float imageY; @end @im ...
- 从零开始学JAVA(09)-使用SpringMVC4 + Mybatis + MySql 例子(注解方式开发)
项目需要,继续学习springmvc,这里加入Mybatis对数据库的访问,并写下一个简单的例子便于以后学习,希望对看的人有帮助.上一篇被移出博客主页,这一篇努力排版整齐,更原创,希望不要再被移出主页 ...
- Pycharm---新建文件时 自动添加作者时间等信息
可用的变量有: $ {PROJECT_NAME} - 当前项目的名称. $ {NAME} - 在文件创建过程中在“新建文件”对话框中指定的新文件的名称. $ {USER} - 当前用户的登录名. $ ...
- AuthenticationManager、ProviderManager
本篇主要讲述以下几点: 1.AuthenticationManager.ProviderManager和AuthenticationProvider三者之间的关系 2.以UsernamePasswor ...
- 定时器--Quartz.Net
这次由于项目的需求:什么定时发送邮件通知,定时筛选取消客户下单未支付的订单 重新捡起定时器,在网上翻来找去找到----Quartz.Net老字号了并不表示它就真的老了哦 github:https:// ...
- 2.移植3.4内核-支持烧写yaffs2,裁剪内核并制作补丁
在上章-制作文件系统,并使内核成功启动jffs2文件系统了 本章主要内容如下: 1)使内核支持yaffs2文件系统 2)裁剪内核 3)制作内核补丁 1.首先获取yaffs2源码(参考git命令使用详解 ...
- 设计模式(19)--Observer(观察者模式)--行为型
作者QQ:1095737364 QQ群:123300273 欢迎加入! 1.模式定义: 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图( ...
- 各类无次数限制的免费API接口整理
各类无次数限制的免费API接口整理,主要是聚合数据上和API Store上的一些,还有一些其他的. 聚合数据提供30大类,160种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免 ...