LeetCode 31 . Next Permutation的理解

LeetCode 讨论区中有一种解法看上去比较清晰,但是一开始不是太容易理解,分享一下自己的理解.

完成这道题分成3部分:

1)找到应该增大的位置i

2)将nums[i] 替换成一个比较大的数 nums[j]

3)将[i+1,末尾]的数都翻转一次

感性的认识:next permutation 是要求 比当前这个数 稍微大一点点点的 那个数 ,那我们肯定是让 后面的位 增大, 比如 123456 ,

肯定是让123456   中的"5" 增大 , 这个5的位置是怎么来的呢? 

理性的推理:我们从上面的例子中可以推理出,我们要增大的位置 一定是 相对靠后的 , 那么就可以 从后往前开始遍历 , 

判断 nums[i] < nums[i+1] 是否成立 , 如果成立的话 , 说明nums[i] 这个位上的数 就可以增大 . 如果不成立 , 那么 i-- 即可 

int i ; //i是当前考察的位置 , 与 i+1位置上的数进行比较
for(i = nums.size() ; i >= 0 ; i-- )
{
    if(nums[i] < nums[i+1])
        break;
}

这样我们就记录了 从后往前数 第一个可以被增大的位置 , 而且可以推断出来的是 :范围[i+1,nums.size()-1] 区间的 数 一定是单调递减的,举个例子: 123459876中 5是第一个从后往前找到的 非递减的位置, 其后面的第6个位置到第9个位置都是单调递减的.

值得注意的点是: i=-1的情况,意味着 整个序列都是单调递减的,那么我们就可以直接进入第3步 , 将987654321 翻转成 123456789 当i >= 0 的情况 ,我们要进入第2步 现在我们完成了第1步

第2步中我们需要把nums[i] 替换成比它本身大的那个数 , 这个数 只能从[i+1,nums.size()-1]的范围中寻找(因为[0,i-1]范围内的数是不能动的),又因为[i+1,nums.size()-1]范围内的数是单调递减的 , 所以,我们可以从 后面开始寻找 第一个 大于 nums[i]的位置 j ,然后swap(nums[i] , nums[j]) ,交换后,[i+1,nums.size()-1]范围的数 仍然是单调递减的 .

举两个例子:123459876可以知道 5 和 6进行交换 123469875

12345987654321可以知道5也和6进行交换 , 12346987554321

这样我们完成了第2步.

对i这个位置上的数进行增大后,我们要让[i+1,nums.size()-1]范围内的数 从小到大排列 , 而现在是 递减的(非严格递减) ,所以最后添加一句reverse(nums.begin()+i+1,nums.end()) ;

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int i ;
        for(i = nums.size()-2 ; i >= 0 ;i--)
        {
            if(nums[i] < nums[i+1])
                break;
        }
        if(i == -1)
        {
            reverse(nums.begin() , nums.end());
            return ;
        }
        int j ;
        for(j = nums.size() -1 ; j > i ; j-- )
        {
            if(nums[j] > nums[i]) 
                break ;
        }
        swap(nums[i],nums[j]);
        reverse(nums.begin() + i + 1 , nums.end());
        return ;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值