[leetcode] 31. 下一个排列

文章目录

  • 题目描述
  • 解题方法
    • 两遍扫描
      • java代码
      • 复杂度分析

题目描述

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3][1,3,2][3,1,2][2,3,1]

整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

例如,arr = [1,2,3] 的下一个排列是 [1,3,2]
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2]
arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。

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

示例 1:

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

示例 2:

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

示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

解题方法

两遍扫描

题目说了原地 修改,只允许使用额外常数空间。那就不能使用额外空间按大小存储数字,只能使用常数空间的变量。

我们需要做的是,找到一种方法,使新排列字典序大于旧排列,但是这个排列变大的幅度要是最小的。具体怎么做呢?我下面简单说一下。

  • 第一步,我们先找到一对最靠近右边较小数较大数较小数较大数左边,较小数较大数不一定相连,找到的较大数是最接近较小数的数。找到之后,我们需要交换两个数的位置。
  • 第二步,我们记录较小数原来的下标位置,交换之后现在这个位置是较大数,这个位置之后的数字都是按照非严格递减排序的,我们需要将后面的数字翻转过来,按照非严格递增排序。还有一种可能是没有找到较小数较大数,原排列本身就是非严格递减的,此时我们直接将原排列翻转过来。

以排列 [ 3 , 6 , 2 [3,6,\color {red} 2 [3,6,2, 3 , 3 3,\color {red}3 3,3, 1 ] 1] 1] 为例:

  • 第一步,我们找到的较小数2,较大数是最靠近右边3,此时,将两个数交换后,原排列变为 [ 3 , 6 , 3 [3,6,\color {red} 3 [3,6,3, 3 , 2 , 1 ] 3, 2, 1] 3,2,1]
  • 第二步,我们将交换后的较大数后面的数字翻转过来,此时原排列变为 [ 3 , 6 , 3 [3,6,\color {red} 3 [3,6,3, 1 , 2 , 3 \color {green} 1, 2, 3 1,2,3 ] ] ]。此排列就是原始整数数组的下一个排列

我描述一下该方法:

  • 第一步,设数组为 a a a,长度为 n n n。我们从后向前找到数组中第一个顺序对 ( i , i + 1 ) (i, i+1) (i,i+1),使得 a [ i ] < a [ i + 1 ] a[i] < a[i+1] a[i]<a[i+1]。此时 [ i + 1 , n ) [i+1, n) [i+1,n)非严格递减排序。 a [ i ] a[i] a[i]即为较小数
  • 第二步,我们从 [ i + 1 , n ) [i+1, n) [i+1,n)中找到最接近 a [ i ] a[i] a[i]较大数 a [ j ] a[j] a[j],并使 a [ j ] a[j] a[j] 尽可能靠右
  • 第三步,此时 [ i + 1 , n ) [i+1, n) [i+1,n)非严格递减排序,我们直接使用双指针翻转区间 [ i + 1 , n ) [i+1, n) [i+1,n),使其变为非严格递增排序。如果没有找到较小数较大数,我们直接将区间 [ 0 , n ) [0, n) [0,n)进行翻转

java代码

public void nextPermutation(int[] nums) {if (nums == null || nums.length < 2) {return;}// 记录反转数组的起始位置int index = -1;for (int i = nums.length - 2; i >= 0; i--) {// 当左边的数比右边的数小时if (nums[i] < nums[i + 1]) {// 交换的数是最后两位if (i == nums.length - 2) {swap(i, i + 1, nums);return;} else {// 比nums[i]大且最接近nums[i]的数的下标int minIndex = i + 1;// nums[i + 1] ~ nums[nums.length - 1]是非严格从大到小排列for (int j = i + 2; j < nums.length; j++) {// 从 nums[i + 1] ~ nums[nums.length - 1]中寻找比nums[i]大且最接近nums[i]的数if (nums[i] < nums[j]) {minIndex = j;} else {break;}}swap(i, minIndex, nums);// 记录反转数组的起始位置index = i + 1;break;}}}int l;int r = nums.length - 1;if (index != -1) {l = index;} else {l = 0;}//从数组下标 l ~ r 进行数组交换while (l < r) {swap(l, r, nums);l++;r--;}
}// 数组下标i和j交换函数
public void swap(int i, int j, int[] nums) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;
}

复杂度分析

时间复杂度: O ( N ) O(N) O(N),设数组长度为 N N N,需要扫描两次数组。
空间复杂度: O ( 1 ) O(1) O(1),只需要存储常数级别的指针和变量。


  • 个人公众号
    个人公众号
  • 个人小游戏
    个人小游戏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/460843.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可靠性测试

1 软件可靠性测试 软件可靠性概述 可靠性&#xff08;reliability&#xff09;是指产品在规定的条件下和规定的时间内完成规定功能的能力。 固有可靠性是通过设计、制造赋予产品的可靠性&#xff1b;使用可靠性既受设计、制造的影响&#xff0c;又受使用条件的影响。一般使用可…

(43)找出中枢整数

文章目录 每日一言题目解题思路法一&#xff1a;法二&#xff1a; 代码法一&#xff1a;法二&#xff1a; 结语 每日一言 即使慢&#xff0c;驰而不息&#xff0c;纵令落后&#xff0c;纵令失败&#xff0c;但一定可以达到他所向往的目标。——鲁迅 题目 题目链接&#xff1a…

如何使用CLZero对HTTP1.1的请求走私攻击向量进行模糊测试

关于CLZero CLZero是一款功能强大的模糊测试工具&#xff0c;该工具可以帮助广大研究人员针对HTTP/1.1 CL.0的请求走私攻击向量进行模糊测试。 工具结构 clzero.py - 工具主脚本&#xff1b; default.py - 包含了大多数标准攻击测试方法和字符&#xff1b; exhaustive.py - 包…

JavaScript流程控制详解之循环结构(倒三角、九九乘法表)

循环结构 在JavaScript中&#xff0c;循环语句指的是在满足某个条件下重复执行 指定的一段代码。若条件结果为true,则重复执行&#xff0c;则进入循环&#xff0c;否则结束循环。 在JavaScript中&#xff0c;循环语句如下&#xff1a; while语句do…while语句for语句 while…

常见关系型数据库产品介绍

更新晚了&#xff0c;不好意思啦&#xff01;继关系型数据库的介绍与历史今天主要和大家分享关系型数据库有哪些产品以及简单的背景介绍。这篇文章介意宝宝们听着舒缓的音乐静静享受。 关系型数据库的产品有很多&#xff0c;下面和大家分享一些比较有名的、使用比较广泛的关系…

GEE详细教程之:将Landsat8与Landsat9影像合成一个影像

1.前言 因项目需求&#xff0c;需要获取一个研究区的Landsat8影像&#xff0c;但Landsat8重复周期长&#xff0c;加之天气的影响&#xff0c;很难获取影像质量较好的影像。Landsat4/5/7的波段顺序与landsat8不同&#xff0c;除此之外&#xff0c;landsat7影像还需要工具进行条带…

解决用DeepL翻译文档后不能编辑问题

第一步&#xff1a;将原始文档另存为.xml格式。 在编辑软件中&#xff0c;选择“文件”-->“另存为”-->选择xml格式。如下图所示&#xff1a; 第二步&#xff1a;使用记事本打开xml文档。 在保存好的xml文档上右击&#xff0c;选择“打开方式”为记事本。如下图所示&a…

Ansible command命令模块 这个模块可以直接在远程主机上执行命令,并将结果返回本主机。

目录 参数介绍练习环境配置主机清单配置无密码链接ping模块 command 命令模块也可以用来安装点东西看个路径 command 指定目录来 指定命令 参数介绍 chdir    # 在执行命令之前&#xff0c;先切换到该目录 executable # 切换shell来执行命令&#xff0c;需要使用命令的绝对…

Get Ready!这些 ALVA 应用即将上线 Vision Pro!

日前&#xff0c;苹果 Vision Pro 正式在美国上市&#xff0c;应用商店首批上线超过 600 款应用程序&#xff0c;出色的显示效果和交互体验&#xff0c;为更多应用提供了全新打开方式。 *图源&#xff1a;Apple 对此&#xff0c;作为全球领先的空间计算技术平台供应商&#xff…

利用路由懒加载和CDN分发策略,对Vue项目进行性能优化

目录 一、Vue项目 二、路由懒加载 三、CDN分发策略 四、如何对Vue项目进行性能优化 一、Vue项目 Vue是一种用于构建用户界面的JavaScript框架&#xff0c;它是一种渐进式框架&#xff0c;可以用于构建单页应用&#xff08;SPA&#xff09;和多页应用。Vue具有简单易学、灵…

【动态规划】【前缀和】【C++算法】LCP 57. 打地鼠

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LCP 57. 打地鼠 勇者面前有一个大小为3*3 的打地鼠游戏机&#xff0c;地鼠将随机出现在各个位置&#xff0c;moles[i] [t,x,y] 表…

Vue3中路由配置Catch all routes (“*“) must .....问题

Vue3中路由配置Catch all routes (“*”) must …问题 文章目录 Vue3中路由配置Catch all routes ("*") must .....问题1. 业务场景描述1. 加载并添加异步路由场景2. vue2中加载并添加异步路由(OK)3. 转vue3后不好使(Error)1. 代码2. 错误 2. 处理方式1. 修改前2. 修…