解题思路:
1.获取信息:
(1)整数数组的排列是将其中的整数按一定顺序排列
(它给出了例子来帮你理解这句话,如下)
例如,arr = [1,2,3]
,以下这些都可以视作 arr
的排列:[1,2,3]
、[1,3,2]
、[3,1,2]
、[2,3,1]
(2)数组的下一排序,就是下一个字典序更大的排序
(它也给出了例子来帮助你理解这句话,如下)
例如,arr = [1,2,3]
的下一个排列是 [1,3,2]
。
类似地,arr = [2,3,1]
的下一个排列是 [3,1,2]
。
而 arr = [3,2,1]
的下一个排列是 [1,2,3]
,因为 [3,2,1]
不存在一个字典序更大的排列。
(3)它会给出一种排列,要求我们将它原地修改为下一排列
2.分析题目:
(1)整数数组的排列,你应该看例子就可以懂得,我就不进行讲解了
(2)字典序,大家还记得字典序吗?
我们在进行字符串的比较的时候,会用到字典序,有没有激起你的回忆呢?没有,也没关系,我会说
字典序,用来衡量对象的大小,我们一般是先比较两个字符串中第一位字符的大小,谁大,谁的字典序就大,如果一样,那就比较下一位,以此类推
那么我们可以知道,靠前的位数,大小的权重比较大
另外字典序的比较,我们应该就知道是什么了吧,不知道也没关系,看看例子就懂了
(3)要求我们将原排列原地修改成下一排列
原地修改:说明禁止了我们使用辅助存储空间,但是说了可以使用额外常数空间(这个额外常数空间其实说了跟没说一样)
下一排列:意味着我们这个下一排列要比原排列大,但两者的字典序是最接近的
(4)重点来咯(先说好,其实我们可以将任意几个数看成一个整体,它们也拥有自己的字典序)(你如果没看懂,也没关系,我在下面的代码也会讲解一遍)
有了这么多个例子,又加深了对题目的了解,咱们应该可以知道它是什么意思了吧
我们知道,要尽量只改变数组后面的几个数的位置才能尽可能接近原排列的字典序的同时且大于它,因为越靠前大小的权重就越大了
那么我们怎么确定要改变后面几个数的位置呢?
前面有两个例子,如下
[ 1, 2, 3],它的下一排列,是[1, 3, 2]
你应该知道,为什么前面那个1不动吧,因为后面可以在保留1为首位的同时,组合成一个字典序更大的下一排列对吧,所以只改变后面两个位置
那怎么确定,后面能不能组合成一个较大的字典序呢?
就是通过它们排列的位置,能改变成一个较大的字典序的情况就是,前面的那个数是小于后面那个数的,所以换过来就可以变成一个较大的字典序了
当我们找到前面的数(p2)比后面的数(p1)小的那个位置的时候,我们就将前面的数(p2)依次与后面的所有的数(>=p1)相比较,找到一个最接近的数,与前面的数(p2)交换位置,再对
前面的数(p2)的后面所有的数按从小到大的顺序排列(因为要保证尽量接近,那就保持最小的字典序)
[3,2,1],它的下一排列,是[1, 2, 3]
你发现没有,一般从小到大排列的部分是最小值,从大到小排列的部分是最小值
你想从小变大,就将从小到大的顺便变成从大到小
你再看看上面的例子和我讲解的那些,是不是会感觉要好一点
3.示例查验:
示例1,示例2和示例3:你可以检验一下自己的思路是否正确
4.尝试编写代码
(1)常规法(平平无奇)
思路:可以想成一个截断的方法,越靠前的数不是大小的权重越大吗?那我们就将前面我们根本用不到的数给切掉,只考虑后面的数,那就新形成了一个数组嘛,我们就求这个数组的下一排列,是不是就简化了一下,反正求下一排列,前面那些权重比较大的数也动不得
要改变的位置就像我上面说的,就那样找出来
你可能有疑惑,是啊,我找出来了,但是,为什么要将前面的数(p2)与它后面的所有的数相比较,找出最接近它的数并且要比前面的数大呢?
因为你是要重排剩下的这些数,它们每一个你都不能漏下,那要排成下一排列,那就只能找一个这样的数,排到最前面,才可以保证,它会变大,但不会变得太大
至于,为什么交换后,要按从小到大的顺序排列后面的所有的数,也是为了尽量不让它变太大,因为是下一排列嘛
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int size=nums.size();//数组的大小
int p1=size-1;//一个放在倒数第一位的指针
int p2=p1-1;//一个放在倒数第二位的指针
while(p2>=0){//从后往前扫描
if(nums[p2]<nums[p1]){//查找前面的数小于后面的数的情况
int cap=INT_MAX;//间隔,我们将它初始化为最大值
int web=p1;//p2与之交换的位置
for(p1;p1<size;p1++){//找到最接近且大于p2的数
if(nums[p1]>nums[p2]&&nums[p1]-nums[p2]<cap){
cap=nums[p1]-nums[p2];
web=p1;
}
}
swap(nums[p2],nums[web]);//交换它们的位置
sort(nums.begin()+p2+1,nums.end());//按从小到大的顺序排列后面的数
return;
}
if(p2==0){//如果数组是最大的字典序
sort(nums.begin(),nums.end());//换成最小的字典序
return;
}
p1--;p2--;
}
}
};
我已经竭尽全力写得更通俗易懂了,希望你能理解这道题,虽然字有点多,但也是有一点作用的
如果我写得太专业化或者太简练,其实我自己是爽了,看着帖子也比较好看,你点进来也比较舒心,但是我害怕不能让你理解,太华而不实也不行
唉,希望能帮上你吧,但也不能忘了,纸上得来终觉浅,绝知此事要躬行