1.1关于题目的理解
将整个数组看成是一个数字
以三个数字1、2、3为例,从小到大一所能够组成的所有的数字为123、132、213、231、312、321
让这些数字按照这个顺序循环出现,找到目前所给的循环中的下一个数字是什么。
1.2我的解法
1)用单调栈,单调栈的目的是找到第一个比某个数字最大/最小的数字
2)将第一个比前面小的数字和单调栈中第一个比其略大的数字互相交换
3)然后将这两个数字中间所有的数字从前往后升序排列统一移动到后面,(移动是不少的时间开销)
1.3优化
直接将2)中的两个数字对换,然后后面其余的数字之直接升序排列
我的代码:
void nextPermutation(vector<int>& nums) {
int i,p;
stack<int> mystack;
bool find = false;
for(i = nums.size() - 1;i >= 0 ;i--){
while(!mystack.empty() &&nums[i] < nums[mystack.top()]){
p = mystack.top();
mystack.pop();
find = true;
}//单调栈,找到第一个从后降序的数字
//但是用单调栈不好,额外开辟了空间,并且本质上任然是相邻两个数字的比较
if(find) break;
else mystack.push(i);
}
if(mystack.size() == nums.size()){
sort(nums.begin(),nums.end());
}//如果从头到尾都是降序,那就改成升序
else if(p - i == 1){//p是较大的下标
int temp = nums[i];
nums[i] = nums[p];
nums[p] = temp;
}
else {
int temp = nums[p];
sort(nums.begin()+i+1,nums.begin()+p-1);//如果sort中间这一段数据为空返回的是什么?
for(int j = 0 ; j < p - i;j++){
nums[i+j+1] = nums[i+j];
}//顺便把p向后移动的同时将
nums[i] = temp;
}
}
比较好的代码
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size()-1;
if (i == 0) return;
//我的欠缺点之一:没有考虑到数组的长度不够的情况
//if(i<=1) return;其实更好
while (i>=1&&nums[i-1]>=nums[i])i--;
//和前一个数字比较,只用一个参数,节约空间
if (i == 0) {
reverse(nums.begin(),nums.end());
return;//直接返回是可以的
}
i = i-1;//其实i-1才是那个第一个比较小的数字的数字
int j = nums.size()-1;
while (nums[j]<=nums[i]) j--;//从后面那堆降序的数字中找到比较小的数字略大的数字
swap(nums[i],nums[j]);
//交换
reverse(nums.begin()+i+1,nums.end());
//直接倒序,觉得这个应该比sort快?
return;
}
};
使用库函数
class Solution {
public:
void nextPermutation(vector<int>& nums) {
// vector<int> origin = nums;
if(next_permutation(nums.begin(),nums.end())){
}else {
sort(nums.begin(),nums.end());
}
}
};