LeetCode 31. 下一个排列(中)
遇到输入序列就是严格降序的,直接返回其升序。 从右往左找到第一对两个连续的数字 a[i] 和 a[i+1],它们满足 a[i]<a[i+1](从后往前找)。此时交换这两个数字,就能得到一个比原来序列更大的组合。接着,去a[i+1]右边找到一个a[j](从后往前找),使得a[j-1]<a[i]<a[j]。这时,交换a[i-1]和a[j],再对a[i]右边的数字进行一次降序排列,就可以了得到结果了。
题目
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
人话版问题描述:给定若干个数字,将其组合为一个整数。如何将这些数字重新排列,以得到下一个更大的整数。如 123 下一个更大的数为 132。如果没有更大的整数,则输出最小的整数。
示例
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1 |
|
考察知识点
数组
核心思想
方法一、 暴力破解法
算法
在这种方法中,我们找出由给定数组的元素形成的列表的每个可能的排列,并找出比给定的排列更大的排列。 但是这个方法是一种非常天真的方法,因为它要求我们找出所有可能的排列 这需要很长时间,实施起来也很复杂。 因此,这种方法根本无法通过。 所以,我们直接采用正确的方法。
复杂度分析
时间复杂度:\(O(n!)\),可能的排列总计有 n! 个。 空间复杂度:\(O(n)\),因为数组将用于存储排列。
方法二、扫描法
代码概述:
1、特判:遇到输入序列就是严格降序的,直接返回其升序。
2、如果输入序列不是严格降序,从右往左找到第一对两个连续的数字 a[i] 和 a[i+1],它们满足 a[i]<a[i+1](从后往前找)。此时交换这两个数字,就能得到一个比原来序列更大的组合,但是,题目要求得到的是下一个不能太大,也就刚好比当前组合大,直接交换a[i]和a[i+1],得到的满足不了条件。如:
1 |
|
3、那要怎么办呢?此时我们知道,a[i+1]右边肯定是严格降序的,否则a[i]不会是第一个满足a[i]>a[i+1]条件的数字,那么就去a[i+1]右边找到一个a[j](从后往前找),使得a[j-1]<a[i]<a[j]。
4、这时,交换a[i-1]和a[j],再对a[i]右边的数字进行一次降序排列,就可以了得到结果了。
整个过程如下:
方法三、D.E. Knuth 算法(待补充)
按照字典顺序生成全排列,在 \(O(N)\) 时间内解决该问题。
Python版本
简单写了一个版本
把问题思考的太简单。通过测试用例 154 / 265。
1 |
|
扫描法实现
1 |
|
时间复杂度:\(O(n)\),在最坏的情况下,只需要对整个数组进行两次扫描。
空间复杂度:\(O(1)\),没有使用额外的空间,原地替换足以做到。
执行用时 :44 ms, 在所有 Python3 提交中击败了77.95%的用户
内存消耗 :13.3 MB, 在所有 Python3 提交中击败了31.28%的用户
有效语法糖
能用while就别用for来控制循环,for循环的启动也是有条件的。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!