一、下一个排列(中)

题目

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

  • 例如,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:
输入:
输出:

示例 2:
输入:
输出:

示例 3:
输入:
输出:

提示:

题解

怎么说呢,首先你得读懂题目。
就是按照升序排序,然后依次选取次大的元素进行排序组合。

举个例子,

所以下一个排列就是

这道题记住思路,就很容易解决。
1、从右开始遍历,先找出第一个索引,满足,如果不存在,就翻转整个数组;
2、再从右开始遍历,找出第二个索引,满足
3、交换
4、最后翻转

比如,下一个排列是什么?
我们找到第一个索引是
再找到第二个索引是
交换,
翻转,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
void nextPermutation(vector<int>& nums) {
if (nums.size() == 0) {
return;
}
int firstIndex = -1;
for (int i = nums.size() - 2; i >= 0; i--) {
if (nums[i] < nums[i + 1]) {
firstIndex = i;
break;
}
}
if (firstIndex == -1) {
reverse(nums.begin(), nums.end());
return;
}
int secondIndex = -1;
for (int i = nums.size() - 1; i > 0; i--) {
if (nums[i] > nums[firstIndex]) {
secondIndex = i;
break;
}
}
int temp = nums[firstIndex];
nums[firstIndex] = nums[secondIndex];
nums[secondIndex] = temp;
reverse(nums.begin() + firstIndex + 1, nums.end());
}
};

二、上一个排列(中)

题目

给定一个整数数组来表示排列,按升序找出其上一个排列。

示例 1:
输入:
输出:

示例 2:
输入:
输出:

示例 3:
输入:
输出:

提示:

题解

跟下一个排列一样,只不过求的是上一个,而不是下一个。

举个例子,

所以上一个排列就是

所以只需要根据第一题的代码,只用把遍历里的>换成<即可。
1、从右开始遍历,先找出第一个索引,满足,如果不存在,就翻转整个数组;
2、再从右开始遍历,找出第二个索引,满足
3、交换
4、最后翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
void prevPermutation(vector<int>& nums) {
if (nums.size() == 0) {
return;
}
int firstIndex = -1;
for (int i = nums.size() - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1]) {
firstIndex = i;
break;
}
}
if (firstIndex == -1) {
reverse(nums.begin(), nums.end());
return;
}
int secondIndex = -1;
for (int i = nums.size() - 1; i > 0; i--) {
if (nums[i] < nums[firstIndex]) {
secondIndex = i;
break;
}
}
int temp = nums[firstIndex];
nums[firstIndex] = nums[secondIndex];
nums[secondIndex] = temp;
reverse(nums.begin() + firstIndex + 1, nums.end());
}
};

三、交换一次的先前排列(中)

题目

给你一个正整数数组 arr(可能存在重复的元素),请你返回可在 一次交换(交换两数字 arr[i] 和 arr[j] 的位置)后得到的、按字典序排列小于 arr 的最大排列。
如果无法这么操作,就请返回原数组。

示例 1:
输入:
输出:
解释:交换 2 和 1

示例 2:
输入:
输出:
解释:已经是最小排列

示例 3:
输入:
输出:
解释:交换 9 和 7

提示:

题解

这题跟我『上一个排列』差不多,主要是它找的排列是两个元素调换位置的,不像『上一个排列』那样,元素可以全部重排。

那首先照搬『上一个排列』解法,最后交换 firstIndex 和 secondIndex ,不用 reverse 逆序排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public:
vector<int> prevPermOpt1(vector<int>& nums) {
if (nums.size() == 0) {
return nums;
}
int firstIndex = -1;
for (int i = nums.size() - 2; i >= 0; i--) {
if (nums[i] > nums[i + 1]) {
firstIndex = i;
break;
}
}
if (firstIndex == -1) {
return nums;
}
int secondIndex = -1;
for (int i = nums.size() - 1; i > 0; i--) {
if (nums[i] < nums[firstIndex]) {
if (nums[i] == nums[i - 1]) {
// 防止有相邻重复元素出现,比如[3,1,1,4]
continue;
}
secondIndex = i;
break;
}
}
int temp = nums[firstIndex];
nums[firstIndex] = nums[secondIndex];
nums[secondIndex] = temp;
return nums;
}
};

©2018 - Felicx 使用 Stellar 创建
总访问 113701 次 | 本页访问 326
共发表 83 篇Blog · 总计 127.5k 字