持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
前言
今天的题目为中等,题目的难点在于理解字典序是什么,以及我们要怎么讲字典序和排列关联到一起。
每日一题
今天的题目是 31. 下一个排列,难度为中等
-
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
-
例如,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
题解
两次交换
在做这道题之前,需要先知道一下什么是字典序,
在数学中,字典或词典顺序(也称为词汇顺序,字典顺序,字母顺序或词典顺序)是基于字母顺序排列的单词按字母顺序排列的方法。 这种泛化主要在于定义有序完全有序集合(通常称为字母表)的元素的序列(通常称为计算机科学中的单词)的总顺序。
字典序在这道题中,代表的就是数字的排序,其中,两两之间的比较就是从左往右进行比较,优先出现某一个数字较大的数组,他的字典序就更大,比方说,[1,2,3] 的 字典序 就要小于 [1,3,2],因为第二位的 2 要比 3 小,那么题目要我们找到一个数组排列的下一个字典序,我们就需要找到能让他字典序增大的排列,并且是影响最小的那一个。
对于字典序来说,越往右的数字大小变化,对其影响就是越小的,比方说有一个字典序:[1,2,5,3,4],让他字典序变大的方法有很多,但是其中影响最小的就是从右边找到一个顺序的两位数,拿到两个数的前一个之后,再从右边开始找到比这个数大的另一个书,交换他们的顺序,也就是 [1,2,5,4,3]。
并且后面的顺序可能还可以在进行更多的调整,在交换完之后,我们已经能够确认这个新的数组的字典序是比之前那个要大的,但是一定是下一个排列,下一个排列的话还要注意除开交换的位置,往右的数一定要是当前最小的情况,也就是升序排列。
比方说 [1,5,2,4,3,2] 在我们找到第一个顺序的两位数也就是 [2,4] 之后,就要从右往左去找第一个比它大的数,也就是 3 这个数,然后交换它们的位置,得到 [1,5,3,4,2,2],但是就能够看出来,这种情况并不是最小的下一个排列,后面的 [4,2,2] 还能够组成更小的字典序,也就是升序排列,这样就能够找到下一个排列 [1,5,3,2,2,4]
/**
Do not return anything, modify nums in-place instead.
*/
function nextPermutation(nums) {
let i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
let j = nums.length - 1;
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
let t = nums[i]
nums[i] = nums[j]
nums[j] = t
// 交换
}
let l = i + 1;
let r = nums.length - 1;
while (l < r) {
let t = nums[l]
nums[l] = nums[r]
nums[r] = t
l++;
r--;
}
}