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

 

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