这个题目的意思结合所给示例以及题目描述,可以知道。给一个数组,求该数组所组成的数字的全排列的下一个数字,这句话不懂没关系,我举个例子你就懂了
例如:
1.若给的是 1 2 3 ,那么你要将数组内容变为 1 3 2;
2.若给的是 3 2 1 ,那么i要见数组的内容变为1 2 3;
其实这是一个循环的排列,就是你给任意的数字排列,都可以找到下一个排列,大概就是这样的情况
如上图,假如你给的数字是,123的全排列的中的一个,那么最后的结果将是这个排列的下一个排列,到这里相信大家理解意思了吧。那么下面就说说题目的解法吧:
1.首先题目不准使用额外的空间,如果可以的话,我们可以求出全排,然后像查表一样就可以了,不过仔细想想这样确实比较低效率,假若所给的数字为100位甚至更多,那么它的全排列将会是多大呢,将会使用很大的空间。
2.这个题目我想了比较长的时间,因为我一看到它的时候就知道,这其实是一个数学规律,只要找到规律了就好办了。我也测试了好几次,然后从错误中找到了规律。规律如下:
1.极端情况,如: 3 2 1
这种情况就可以直接将数组排序即可
2.最喜欢的情况: 1 2 3
这种情况只需要将2与3互换位置
3.平常且难想的情况: 假如给的数组序列为: 5 4 7 5 3 2
此时我们该如何动手呢?好了,这个时候就是展现真正本领的时候了....
请注意,上面的情况中5 4 7 5 3 2 序列中是蓝色的有序的,即依次降序,可以说明,这个时候5 4 7 5 3 2所组成的数字是最大的(绿色部分),所以下一步是找到比这个数字更大的数字,那么只能往前考虑了,即把4加入到 54 7 5 3 2 中,那么就是 54 7 5 3 2,意思就是找到比5 4 7 5 3 2大的数字中的最小的一个。用肉眼去看,是 55 2 3 4 7 所以我们是找到了比5 4 7 5 3 2 大的数字中的最小的一个,方法是在黄色序列中(7 5 3 2)找到比红色(4)大的数字中最小的一个,然后互换两者的位置 5 57 4 3 2 ,还没完,此时还不是索要找的数字。将蓝色部分排序后 : 5 5 2 3 4 7,这就是慢要求的下一个数字。
到此我们可以开始系代码了,思路是,从后往前找,假设此时pos是最后一个位置,当我们找到pos-1位置比pos位置小的时候停止,那么这个时候pos位置以后的部分时有序的,如:
* 这个时候,再从右边的序列中找到比pos-1位置大的元素,交换两者,然后排序即可。
* 若pos指向 0 了,则说明该情况类似 3 2 1,我们将整个排序即可。
* 若pos的位置还是在最后一个,即 123 的情况,这儿时候交换pos和pos-1的位置即可。
代码:
class Solution {
public:
void nextPermutation(vector<int>& nums)
{
int len = nums.size();
if (len == 0 || len == 1)
{
return;
}
//从尾部向前找,找到nums[pos] > nums[pos-1]位置
int pos = len - 1;
while (pos > 0 && nums[pos] <= nums[pos - 1])
{
--pos;
}
if (pos == 0)
{//说明到了最后一个位置,例如 3 2 1 ,此时将它排序即可
sort(nums.begin(), nums.end());
return;
}
else
{
if (pos == len - 1)
{//pos 在最后一个位置,例如 1 2 3 ,那么此时将nums[pos]与nums[pos-1]互换即可
swap(nums[pos], nums[pos - 1]);
return;
}
else
{ //这种情况说明pos在中间位置,举例吧,如:5 4 7 5 3 2
int key = nums[pos - 1];
//找比key值大的数字,即比4大的数,可以看到是5(后面的5)
int begin = len - 1;
while (begin > pos && nums[begin] <= key)
{
--begin;
}
//此时 begin 位置的数字比 key 值大,因为至少pos位置的数比key值大,而且从pos到len-1之间的数字是降序的
swap(nums[pos - 1], nums[begin]);
//swap以后序列为 5 5 7 4 3 2,然后从pos位置到len-1位置排序,即7~2排序
sort(nums.begin() + pos, nums.end());
return;
}
}
}
};
相应的结果如下:
相信这个题带啊看懂了吧,如果还不明白的话,那么就得拿笔在纸上画画看吧。