3803 字
约 12 分钟
6
LeetCode刷题Java版031.下一个排列
无标签

LeetCode刷题Java版031.下一个排列

作者:沉默王二
发布时间:2022-08-25T07:29:20.941+0800


031.下一个排列

题意

给你一个数组,让你求其字典序意义上的更大一个的排列,如果已经是最大的字典序,则返回最小的字典序。

题意似乎有些难理解,因为第一次看到“字典序”这个概念的时候,不能很好的理解它表达的意思。不过没关系,看一下示例和分析你就明白了。

难度

中等

示例

例1

输入:nums = [1,2,3]

例2

输入:nums = [3,2,1]

分析

字典序(dictionary order),又称 字母序(alphabetical order),原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。而这道题目中,字典序其实是指☞ 数字大小的先后顺序。

理解了“字典序”,就能很快理解这道题的题意了:要我们求出比这个数更大的一个排列,比如 123,比它大的是 132,对吧?只需要改变 23 的位置就可以了。312 也比 123 大,只不过它是比 132 更大的一个,不是比 123 更大的一个。

再比如 321 已经是这个组合中最大的那个了,那就等于说没有更大的了,所以返回 123 这个最小的。

明白了吧?

要想解题,首先得明白题意,所以语文理解是非常重要的,其次是经验。

那凭我们的经验,可能一下子会想到全排列,然后再挨个找,最后输出这个排列的下一个排列,可惜这样子时间复杂度太高了——也就是,实在是顶不住啊!

但是没关系,我们先来观察一下数组(就拿 1、2、3、4 来举例吧)的全排列:

nums = [1,2,3,4]

nums = [1,3,2,4]nums = [1,3,4,2]nums = [1,4,2,3]nums = [1,4,3,2]nums = [2,1,3,4]nums = [2,1,4,3]nums = [2,3,1,4]nums = [2,3,4,1]nums = [2,4,1,3]nums = [2,4,3,1]nums = [3,1,2,4]nums = [3,1,4,2]nums = [3,2,1,4]nums = [3,2,4,1]nums = [3,4,1,2]nums = [3,4,2,1]nums = [4,1,2,3]nums = [4,1,3,2]nums = [4,2,1,3]nums = [4,2,3,1]nums = [4,3,1,2]nums = [4,3,2,1]

这道题中,我们可以把字典序理解成一个进制为INF的一个数字,这样子就可以比较直观的比较大小了。而下一个排列,就是要你用现在已有的数字组合出一个 恰好 比它大的一个新的进制为INF的数字。而且要让这个新的数尽可能小。

观察nums = [1,3,4,2] -> nums = [1,4,2,3]这一步,因为4比3大,且4的位置在3之后,所以将4与3交换,必然能够使得nums变大,交换了之后,则变成了nums = [1,4,3,2]。

我们看一下上面列出来的范例,显然这不是最小的比nums = [1,3,4,2]大的一个排列,我们还要把3和2的位置再翻转一下,才能得到nums = [1,4,2,3]这个 恰好 比nums = [1,3,4,2]大的排列。

但是我们不能直接交换1和3,因为这样子迈的步子有点大,有没有快速找到两个需要交换的数字的一个标准呢?

观察上面的全排列,我们不难得出,需要寻找的是一个从右到左的第一个nums[i] < nums[i + 1]的数字,而这时候,我们能够保证[i + 1,nums.length )必然是下降的。

有些小伙伴,可能会想着——直接交换nums[i]和nums[i + 1],这样子可行吗?

事实上不行,因为我们为了让新的数列最小,不能直接交换二者,因为如果[i + 1,nums.length )中存在有一个nums[k]比nums[i]大,且同时比nums[i + 1]小的数字,显然直接交换nums[i]和nums[k]更合理一点,因为它交换之后是比交换nums[i]和nums[i + 1]更小。

所以到这里,这道题目就迎刃而解了。

具体代码实现:

class Solution {

        int temp = nums[posI];        nums[posI] = nums[posJ];        nums[posJ] = temp;    }    private void reverse(int[] nums, int lef, int rig){        while(lef < rig){            swap(nums,lef,rig);            lef++;            rig--;        }    }    public void nextPermutation(int[] nums) {        int pos1 = nums.length - 2;        while(pos1 >= 0 && nums[pos1] >= nums[pos1 + 1])            pos1--;        if(pos1 == -1){            reverse(nums,0,nums.length - 1);            return ;        }        int pos2 = nums.length - 1;        for(int i = nums.length - 1;i >= 0;i--){            if(nums[i] > nums[pos1]){                pos2 = i;                break;            }        }        swap(nums,pos1,pos2);        reverse(nums,pos1 + 1,nums.length - 1);    }}

效率嘛,自然是快得飞起,因为我们只是扫描了一下数组,只需要的时间复杂度即可。

总结

本题如果直接 莽 ,去求所有的排列的话,我想可能没有哪个CPU能够在我们预期的时间内给出答案。我们之所以学习算法,就是想让我们拥有更快的能够解决问题的方法。硬件的进步是时代的进步,而我们个人的智慧,才能够使我们脱颖而出。

力扣链接:https://leetcode.cn/problems/next-permutation/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 700 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

031.下一个排列

题意

给你一个数组,让你求其字典序意义上的更大一个的排列,如果已经是最大的字典序,则返回最小的字典序。

题意似乎有些难理解,因为第一次看到“字典序”这个概念的时候,不能很好的理解它表达的意思。不过没关系,看一下示例和分析你就明白了。

难度

中等

示例

例1

输入:nums = [1,2,3]

例2

输入:nums = [3,2,1]

分析

字典序(dictionary order),又称 字母序(alphabetical order),原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。而这道题目中,字典序其实是指☞ 数字大小的先后顺序。

理解了“字典序”,就能很快理解这道题的题意了:要我们求出比这个数更大的一个排列,比如 123,比它大的是 132,对吧?只需要改变 23 的位置就可以了。312 也比 123 大,只不过它是比 132 更大的一个,不是比 123 更大的一个。

再比如 321 已经是这个组合中最大的那个了,那就等于说没有更大的了,所以返回 123 这个最小的。

明白了吧?

要想解题,首先得明白题意,所以语文理解是非常重要的,其次是经验。

那凭我们的经验,可能一下子会想到全排列,然后再挨个找,最后输出这个排列的下一个排列,可惜这样子时间复杂度太高了——也就是,实在是顶不住啊!

但是没关系,我们先来观察一下数组(就拿 1、2、3、4 来举例吧)的全排列:

nums = [1,2,3,4]

nums = [1,3,2,4]nums = [1,3,4,2]nums = [1,4,2,3]nums = [1,4,3,2]nums = [2,1,3,4]nums = [2,1,4,3]nums = [2,3,1,4]nums = [2,3,4,1]nums = [2,4,1,3]nums = [2,4,3,1]nums = [3,1,2,4]nums = [3,1,4,2]nums = [3,2,1,4]nums = [3,2,4,1]nums = [3,4,1,2]nums = [3,4,2,1]nums = [4,1,2,3]nums = [4,1,3,2]nums = [4,2,1,3]nums = [4,2,3,1]nums = [4,3,1,2]nums = [4,3,2,1]

这道题中,我们可以把字典序理解成一个进制为INF的一个数字,这样子就可以比较直观的比较大小了。而下一个排列,就是要你用现在已有的数字组合出一个 恰好 比它大的一个新的进制为INF的数字。而且要让这个新的数尽可能小。

观察nums = [1,3,4,2] -> nums = [1,4,2,3]这一步,因为4比3大,且4的位置在3之后,所以将4与3交换,必然能够使得nums变大,交换了之后,则变成了nums = [1,4,3,2]。

我们看一下上面列出来的范例,显然这不是最小的比nums = [1,3,4,2]大的一个排列,我们还要把3和2的位置再翻转一下,才能得到nums = [1,4,2,3]这个 恰好 比nums = [1,3,4,2]大的排列。

但是我们不能直接交换1和3,因为这样子迈的步子有点大,有没有快速找到两个需要交换的数字的一个标准呢?

观察上面的全排列,我们不难得出,需要寻找的是一个从右到左的第一个nums[i] < nums[i + 1]的数字,而这时候,我们能够保证[i + 1,nums.length )必然是下降的。

有些小伙伴,可能会想着——直接交换nums[i]和nums[i + 1],这样子可行吗?

事实上不行,因为我们为了让新的数列最小,不能直接交换二者,因为如果[i + 1,nums.length )中存在有一个nums[k]比nums[i]大,且同时比nums[i + 1]小的数字,显然直接交换nums[i]和nums[k]更合理一点,因为它交换之后是比交换nums[i]和nums[i + 1]更小。

所以到这里,这道题目就迎刃而解了。

具体代码实现:

class Solution {

        int temp = nums[posI];        nums[posI] = nums[posJ];        nums[posJ] = temp;    }    private void reverse(int[] nums, int lef, int rig){        while(lef < rig){            swap(nums,lef,rig);            lef++;            rig--;        }    }    public void nextPermutation(int[] nums) {        int pos1 = nums.length - 2;        while(pos1 >= 0 && nums[pos1] >= nums[pos1 + 1])            pos1--;        if(pos1 == -1){            reverse(nums,0,nums.length - 1);            return ;        }        int pos2 = nums.length - 1;        for(int i = nums.length - 1;i >= 0;i--){            if(nums[i] > nums[pos1]){                pos2 = i;                break;            }        }        swap(nums,pos1,pos2);        reverse(nums,pos1 + 1,nums.length - 1);    }}

效率嘛,自然是快得飞起,因为我们只是扫描了一下数组,只需要的时间复杂度即可。

总结

本题如果直接 莽 ,去求所有的排列的话,我想可能没有哪个CPU能够在我们预期的时间内给出答案。我们之所以学习算法,就是想让我们拥有更快的能够解决问题的方法。硬件的进步是时代的进步,而我们个人的智慧,才能够使我们脱颖而出。

力扣链接:https://leetcode.cn/problems/next-permutation/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 700 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

031.下一个排列

题意

给你一个数组,让你求其字典序意义上的更大一个的排列,如果已经是最大的字典序,则返回最小的字典序。

题意似乎有些难理解,因为第一次看到“字典序”这个概念的时候,不能很好的理解它表达的意思。不过没关系,看一下示例和分析你就明白了。

难度

中等

示例

例1

输入:nums = [1,2,3]

例2

输入:nums = [3,2,1]

分析

字典序(dictionary order),又称 字母序(alphabetical order),原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。而这道题目中,字典序其实是指☞ 数字大小的先后顺序。

理解了“字典序”,就能很快理解这道题的题意了:要我们求出比这个数更大的一个排列,比如 123,比它大的是 132,对吧?只需要改变 23 的位置就可以了。312 也比 123 大,只不过它是比 132 更大的一个,不是比 123 更大的一个。

再比如 321 已经是这个组合中最大的那个了,那就等于说没有更大的了,所以返回 123 这个最小的。

明白了吧?

要想解题,首先得明白题意,所以语文理解是非常重要的,其次是经验。

那凭我们的经验,可能一下子会想到全排列,然后再挨个找,最后输出这个排列的下一个排列,可惜这样子时间复杂度太高了——也就是,实在是顶不住啊!

但是没关系,我们先来观察一下数组(就拿 1、2、3、4 来举例吧)的全排列:

nums = [1,2,3,4]

nums = [1,3,2,4]nums = [1,3,4,2]nums = [1,4,2,3]nums = [1,4,3,2]nums = [2,1,3,4]nums = [2,1,4,3]nums = [2,3,1,4]nums = [2,3,4,1]nums = [2,4,1,3]nums = [2,4,3,1]nums = [3,1,2,4]nums = [3,1,4,2]nums = [3,2,1,4]nums = [3,2,4,1]nums = [3,4,1,2]nums = [3,4,2,1]nums = [4,1,2,3]nums = [4,1,3,2]nums = [4,2,1,3]nums = [4,2,3,1]nums = [4,3,1,2]nums = [4,3,2,1]

这道题中,我们可以把字典序理解成一个进制为INF的一个数字,这样子就可以比较直观的比较大小了。而下一个排列,就是要你用现在已有的数字组合出一个 恰好 比它大的一个新的进制为INF的数字。而且要让这个新的数尽可能小。

观察nums = [1,3,4,2] -> nums = [1,4,2,3]这一步,因为4比3大,且4的位置在3之后,所以将4与3交换,必然能够使得nums变大,交换了之后,则变成了nums = [1,4,3,2]。

我们看一下上面列出来的范例,显然这不是最小的比nums = [1,3,4,2]大的一个排列,我们还要把3和2的位置再翻转一下,才能得到nums = [1,4,2,3]这个 恰好 比nums = [1,3,4,2]大的排列。

但是我们不能直接交换1和3,因为这样子迈的步子有点大,有没有快速找到两个需要交换的数字的一个标准呢?

观察上面的全排列,我们不难得出,需要寻找的是一个从右到左的第一个nums[i] < nums[i + 1]的数字,而这时候,我们能够保证[i + 1,nums.length )必然是下降的。

有些小伙伴,可能会想着——直接交换nums[i]和nums[i + 1],这样子可行吗?

事实上不行,因为我们为了让新的数列最小,不能直接交换二者,因为如果[i + 1,nums.length )中存在有一个nums[k]比nums[i]大,且同时比nums[i + 1]小的数字,显然直接交换nums[i]和nums[k]更合理一点,因为它交换之后是比交换nums[i]和nums[i + 1]更小。

所以到这里,这道题目就迎刃而解了。

具体代码实现:

class Solution {

        int temp = nums[posI];        nums[posI] = nums[posJ];        nums[posJ] = temp;    }    private void reverse(int[] nums, int lef, int rig){        while(lef < rig){            swap(nums,lef,rig);            lef++;            rig--;        }    }    public void nextPermutation(int[] nums) {        int pos1 = nums.length - 2;        while(pos1 >= 0 && nums[pos1] >= nums[pos1 + 1])            pos1--;        if(pos1 == -1){            reverse(nums,0,nums.length - 1);            return ;        }        int pos2 = nums.length - 1;        for(int i = nums.length - 1;i >= 0;i--){            if(nums[i] > nums[pos1]){                pos2 = i;                break;            }        }        swap(nums,pos1,pos2);        reverse(nums,pos1 + 1,nums.length - 1);    }}

效率嘛,自然是快得飞起,因为我们只是扫描了一下数组,只需要的时间复杂度即可。

总结

本题如果直接 莽 ,去求所有的排列的话,我想可能没有哪个CPU能够在我们预期的时间内给出答案。我们之所以学习算法,就是想让我们拥有更快的能够解决问题的方法。硬件的进步是时代的进步,而我们个人的智慧,才能够使我们脱颖而出。

力扣链接:https://leetcode.cn/problems/next-permutation/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 700 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

            知识星球
            
    
    
        
        扫码加入星球
        查看更多优质内容
    
    https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412
LeetCode刷题Java版031.下一个排列
https://clxhxhhr.top/posts/2495/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。