原题网址:https://www.lintcode.com/problem/previous-permutation/description
描述
给定一个整数数组来表示排列,找出其上一个排列。
排列中可能包含重复的整数
样例
给出排列[1,3,2,3]
,其上一个排列是[1,2,3,3]
给出排列[1,2,3,4]
,其上一个排列是[4,3,2,1]
思路:
首先应该清楚什么是上一个排列,可以参考全排列字典顺序 全排列的实现方法--递归&字典序 与 【C++】全排列之非递归算法——字典序法(2)
理解了全排列字典序后,下一个排列很容易找到,那怎么找上一个排列呢?
思路与寻找下一个排列类似,只不过过程相反。首先,从右向左开始找,找到第一个nums【i】>nums【i+1】的位置i ,即找到从右向左递减序列的前一个位置(结束递减序列的位置),该位置为第一个需要改变字符的位置t;
注意,t+1~end 部分的元素不一定全小于nums【t】,所以需要从右向左找到第一个小于nums【t】的元素位置k,因这部分元素从右向左递减所以nums【k】为 t+1~end 部分小于nums【t】的数中最接近nums【t】的(找最接近nums【t】的是因为要找的是紧邻的上一个排列);
交换nums【t】与nums【k】;
将 t+1 ~ end 部分的元素翻转;(从右向左递减变为递增,保证该排列是原排列紧邻的上一个排列);
PS:数字序列的排序与整数的排序一致,比如123<132<213<……<321,可以是排列的大小,也可以是整数的大小,有了这个认知后就很方便理解为什么求上一个排列或下一个排列要从右往左寻找变位了,因为数字的依次增大或减小总是从低位开始的,累加到一定程度才会反映到高位上。
AC代码:
class Solution { public: /* * @param nums: A list of integers * @return: A list of integers that's previous permuation */ vector<int> previousPermuation(vector<int> &nums) { // write your code here vector<int> result=nums; int n=nums.size(); int t=-1; for (int i=n-2;i>=0;i--) { if (result[i]>result[i+1]) { t=i; break; } } if (t==-1) { reverse(result.begin(),result.end()); } else { int k; for (int j=n-1;j>t;j--) { if (result[j]<result[t]) { k=j; break; } } swap(result[t],result[k]); reverse(result.begin()+t+1,result.end()); } return result; } };
其他方法:
https://blog.csdn.net/guoziqing506/article/details/51870732
http://www.bubuko.com/infodetail-1310249.html
这个答案后面有错,【比如:40712389 右到左递减序列的前一个位置是peakInd = 2 ,3到7内左到右第一个大于7的数是8,其位置是6,交换这个两个位置的数后:40812379,下面在对3 到7位置内的数进行逆序后:40897321.就是答案了。】
应该是【比如:40712389 右到左递减序列的前一个位置是peakInd = 2 ,9到1从右向左第一个小于7的数是3,其位置是5,交换这个两个位置的数后:40312789,下面在对1 到9位置内的数进行逆序后:40398721.就是答案了。】