leetcode No31. Next Permutation

来源:互联网 发布:足球和篮球知乎 编辑:程序博客网 时间:2024/05/16 07:46

Question:

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

题目大意是求下一个全排列

Algorithm:

首先要知道什么是全排列
Ex:1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1
我们先从简单的来找规律,从后往前看
(1)1,2,3的下一个是1,3,2,非递增点3,交换2,3
(2)1,3,2的下一个是2,1,3,非递增点1,交换1,2
(3)2,1,3的下一个是2,3,1,非递增点1,交换1,3
(4)2,3,1的下一个是3,1,2,非递增点2,交换2,3,然后1,2排序
(5)3,1,2的下一个是3,2,1,非递增点2,交换1,2
(6)3,2,1的下一个是1,2,3,逆序
首先我们肯定是从后往前扫,找到非递增的那个点tmp,然后和后面比tmp大中最小的数交换,最后对tmp后的数排序。

Accepted Code:

class Solution {//全排列的下一列,从后往前看,找到递增的转折点public:    void nextPermutation(vector<int>& nums) {        int N=nums.size();    if (N<=1)return;    int point=N-1;    while (nums[point]<=nums[point - 1] && point>0)  //从后面往前扫,找到非递增的点    point--;    if (point == 0)       //特殊情况,逆序    {    sort(nums.begin(), nums.end());    return;    }    else if (point == N - 1)   //特殊情况,顺序    {    swap(nums[N - 1], nums[N - 2]);    return;    }    else    {    point--;        int i=point+1;    for(;i<N;i++)      //找到转折点后面比转折点大的数中最小的一个,下标为i    {    if (nums[point]>=nums[i])    break;    }    i--;    swap(nums[i], nums[point]);   //交换转折点和nums[i]    sort(nums.begin()+point+1, nums.end());   //对转折点后的元素排序    return;    }    }};

2016/12/19更新
学习STL的做法:
令第一个元素为*i,第二个元素为*ii,且满足*i<*ii。找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将i,j元素对调,再将ii之后的所有元素颠倒排序。
class Solution {public:    void nextPermutation(vector<int>& nums) {        vector<int>::iterator first=nums.begin();        vector<int>::iterator last=nums.end();        if(first==last)      //empty            return;        vector<int>::iterator i=first;        i++;        if(i==last)    //only one element            return;        i=last;        //i指向尾端        i--;                   for(;;)        {            vector<int>::iterator ii=i;            --i;   //锁定一组(两个)相邻元素            if(*i<*ii)   //如果前一个元素小于后一个元素            {                vector<int>::iterator j=last;    //j指向尾端                while(!(*i < *--j));             //从尾端往前找,直到比*i大的元素                iter_swap(i,j);                reverse(ii,last);                return;            }            if(i==first)            {                reverse(first,last);                return;            }        }    }};





0 0