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 ;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章