leetcode31——下一个排列

image
image

思路

令待交换的两个数为“小数”和“大数”
1. 从后往前找第一个升序对i,j使得nums[i]<nums[j]。“小数”就是nums[i]。此时[j,end)必然是降序
2. 再从后往前找一个比“小数”大的数作为“大数”,交换二者
3. 交换后将“大数”后的所有数重新排为升序:此时[j,end]仍必为降序,所以逆置即可

疑难点:

  1. 为什么从后往前找:尽可能让交换后的排列更小

比如1243 ,交换2和3为1342肯定比交换1和2为2143好

  1. 为什么是第一个升序对:降序对交换后的排列比原来更小

比如321,交换21为312

  1. 为什么还要再往前找一次:(j,end]之间是降序,想让待交换的大数尽可能小的同时又比待交换的小数要大

比如5764,此时i=0,j=1,直接交换为7564,而选比7小的又比5大的数交换比如6为6754就会更小

总结:

  1. 从后往前找第一个升序对i,j。nums[i]就是小数
  2. 再在[j,end]从后往前找一个比小数大的作为大数,交换二者
  3. 把大数后的所以数逆置reverse

代码

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
	// 从后往前找第一个升序对
        int i = nums.size() - 2;
        while(i >=0 && nums[i] >= nums[i+1]){
            i--;
        }
	// 如果nums是321这种则i=-1,直接reverse
	// 否则再从后往前找真正的大数
        if(i>=0){
            int j = nums.size()-1;
            while(j >= i+1 && nums[j] <= nums[i]){ // >= i+1更好理解
                j--;
            }
            swap(nums[i],nums[j]);
        }
        reverse(nums.begin() + i + 1,nums.end());
    }
};
posted @   NeroMegumi  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示