leetcode第31题

简介: 我们想几个问题。要想使得数字变大,只要任意一位变大就可以。要想得到刚好大于原来的数字,要变个位。这里变大数字,只能利用交换。如果从个位开始,从右往左进行,找一个比个位大的,交换过来,个位的数字交换到了更高位,由于个位的数字较小,所以交换过去虽然个位变大了,但数字整体变小了。例如 1 3 2,把 2 和 3 交换,变成 1 2 3,个位变大了,但整体数字变小了。个位不行,我们再看十位,如果从十位左边找一个更大的数字交换过来,和个位的情况是一样的,数字会变小。例如 4 1 2 3,把 2 和 4 交换,2 1 4 3,数字会变小。如果从

image.png

这道题的的难度我觉得理解题意就占了一半。题目的意思是给定一个数,然后将这些数字的位置重新排列,得到一个刚好比原数字大的一种排列。如果没有比原数字大的,就升序输出。

关键就是刚好是什么意思?比如说原数字是 A,然后将原数字的每位重新排列产生了 B C D E,然后把这 5 个数字从小到大排列,比如是 D A B E C ,那么,我们要找的就是 B,就是那个刚好比 A 大的数字。

再比如 123,其他排列有 132,213,231,312,321,从小到大排列就是 123 132 213 231 312 321,那么我们要找的就是 132。

题目还要求空间复杂度必须是 O(1)。

解法一

我们想几个问题。

要想使得数字变大,只要任意一位变大就可以。

要想得到刚好大于原来的数字,要变个位。

这里变大数字,只能利用交换。

如果从个位开始,从右往左进行,找一个比个位大的,交换过来,个位的数字交换到了更高位,由于个位的数字较小,所以交换过去虽然个位变大了,但数字整体变小了。例如 1 3 2,把 2 和 3 交换,变成 1 2 3,个位变大了,但整体数字变小了。

个位不行,我们再看十位,如果从十位左边找一个更大的数字交换过来,和个位的情况是一样的,数字会变小。例如 4 1 2 3,把 2 和 4 交换,2 1 4 3,数字会变小。如果从右边找一个更大的数字交换过来,由于是从低位交换过来的,所以数字满足了会变大。如 4 1 2 3,把 2 和 3 交换,变成 4 1 3 2 数字变大了。

如果十位右边没有比十位数字大的,我们就左移看下一位,再看当前位右边,有没有更大的数字,没有就一直左移就可以。

还有一个问题,如果右边有不止一个大于当前位的数字选哪个?选那个刚好大于当前位的,这样会保证数字整体尽可能的小。

交换完结束了吗?并没有。因为交换完数字变大了,但并不一定是刚好大于原数字的。例如 158476531,我们从十位开始,十位右边没有大于 3 的。再看百位,百位右边没有大于 5 的。直到 4 ,右边出现了很多大于 4 的,选那个刚好大于 4 的,也就是 5 。然后交换,变成 158576431,数字变大了,但并不是刚好大于 158476531,我们还需要将 5 右边的数字从小到大排列。变成158513467,就可以结束了。

而最后的排序,我们其实并不需要用排序函数,因为交换的位置也就是 5 的右边的数字一定是降序的,我们只需要倒序即可了。看一下 LeetCode 提供的动图更好理解一些。

image.png

再看这个过程,我们其实是从右向左找到第一个数字不再递增的位置,然后从右边找到一个刚好大于当前位的数字即可。

再看下代码吧。

publicvoidnextPermutation(int[] nums) {
inti=nums.length-2;
//找到第一个不再递增的位置while (i>=0&&nums[i+1] <=nums[i]) {
i--;
    }
//如果到了最左边,就直接倒置输出if (i<0) {
reverse(nums, 0);
return;
    }
//找到刚好大于 nums[i]的位置intj=nums.length-1;
while (j>=0&&nums[j] <=nums[i]) {
j--;
    }
//交换swap(nums, i, j);
//利用倒置进行排序reverse(nums, i+1);
}
privatevoidswap(int[] nums, inti, intj) {
inttemp=nums[j];
nums[j] =nums[i];
nums[i] =temp;
}
privatevoidreverse(int[] nums, intstart) {
inti=start, j=nums.length-1;
while (i<j) {
swap(nums, i, j);
i++;
j--;
    }
}

时间复杂度:最坏的情况就是遍历完所有位,O(n),倒置也是 O(n),所以总体依旧是 O(n)。

空间复杂度:O(1)。

开始看题的时候一直没理解,后来理解了题试了几种也没想出来,然后看了 Solution,理了下思路

相关文章
|
7月前
LeetCode
LeetCode
42 0
|
7月前
|
消息中间件 Kubernetes NoSQL
LeetCode 1359、1360
LeetCode 1359、1360
|
Python
LeetCode 1904. 你完成的完整对局数
一款新的在线电子游戏在近期发布,在该电子游戏中,以 刻钟 为周期规划若干时长为 15 分钟 的游戏对局。这意味着,在 HH:00、HH:15、HH:30 和 HH:45 ,将会开始一个新的对局,其中 HH 用一个从 00 到 23 的整数表示。游戏中使用 24 小时制的时钟 ,所以一天中最早的时间是 00:00 ,最晚的时间是 23:59 。
106 0
|
存储 Python
LeetCode 66. Plus One
给定表示非负整数的非空数字数组,加上整数的1。 存储数字使得最高有效数字位于列表的开头,并且数组中的每个元素包含单个数字。 您可以假设整数不包含任何前导零,除了数字0本身。
92 0
LeetCode 66. Plus One
|
算法
LeetCode——944. 删列造序
LeetCode——944. 删列造序
111 0
|
算法 Java
一和零(LeetCode 474)
一和零(LeetCode 474)
102 0
leetcode第53题
解法一和解法二的动态规划,只是在定义的时候一个表示以 i 开头的子数组,一个表示以 i 结尾的子数组,却造成了时间复杂度的差异。问题就是解法一中求出了太多的没必要的和,不如解法二直接,只保存最大的和。
leetcode第53题
leetcode第36题
一个 9 * 9 的数独的棋盘。判断已经写入数字的棋盘是不是合法。需要满足下边三点, • 每一行的数字不能重复 • 每一列的数字不能重复 • 9 个 3 * 3 的小棋盘中的数字也不能重复。 只能是 1 - 9 中的数字,不需要考虑数独最后能不能填满
leetcode第36题
|
存储
leetcode第52题
可以发现对于同一条副对角线,row + col 的值是相等的。 对于同一条主对角线,row - col 的值是相等的。 我们同样可以用一个 bool 型数组,来保存当前对角线是否有元素,把它们相加相减的值作为下标。 对于 row - col ,由于出现了负数,所以可以加 1 个 n,由 [ - 3, 3 ] 转换为 [ 1 , 7 ] 。
leetcode第52题
leetcode第39题
对回溯法又有了更深的了解,一般的架构就是一个大的 for 循环,然后先 add,接着利用递归进行向前遍历,然后再 remove ,继续循环。而解法二的动态规划就是一定要找到递进的规则,开始的时候就想偏了,导致迟迟想不出来。
leetcode第39题