實現獲取下乙個排列的函式,演算法需要將給定數字序列重新排列成字典序中下乙個更大的排列。
如果不存在下乙個更大的排列,則將數字重新排列成最小的排列(即公升序排列)。
必須原地修改,只允許使用額外常數空間。
示例:
輸入 → 輸出
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
舉乙個具體的例子來說明查詢的思路,比如:2,5,6,9,7,0。
要找到其下乙個排列,應該保持該序列的前半部分盡可能不變,然後交換後半部分的某些序列,因此查詢交換位置的操作需要從序列末尾開始,也就是從例子中的 0 開始。
那麼哪個交換位置是滿足要求的呢?我們要查詢的是比原序列稍微大一點的序列,因此從後往前查詢交換位置的時候,只要找到第乙個相鄰公升序對(即相鄰兩個元素是公升序排列的),將公升序對中較小的那個數字使用乙個比它大一點的數字替換即可。也就是找到6,9公升序對,然後找到乙個比 6 稍微大一點的數字替換。
(ps:為什麼要找相鄰公升序對?反過來想,如果在序列中找不到一對相鄰公升序對,則代表該序列本身就是逆序的,比如: 9,7,6,5,2,0,那麼我們不可能找到比該序列更大的序列,該序列的下乙個序列就是最小的排列了。因此只要存在相鄰公升序對,我們就可以找到它,並替換掉小一點的那個數字,從而得到比它大一點的序列。)
那麼從**找那個比 6 稍微大一點的數字呢?首先我們要求原序列的前半部分保持不變,因此我們只能從 6 的後面部分找, 因為 6,9 是第乙個相鄰公升序對,因此 6 後面的序列都是逆序排布的,那麼我們從序列末尾開始查詢,找到的第乙個比 6 大的數字一定是原序列後面部分最靠近 6 還比 6 大的數字,用它替換 6 就沒問題了。此步驟我們得到的序列就是2,5,7,9,6,0。
但這時我們發現該序列並不是最靠近 2,5,6,9,7,0 的序列呀,比它更靠近原序列的還有[ 2,5,7,0,6,9 ]、[ 2,5,7,0,9,6 ]、[ 2,5,7,6,0,9 ]和[ 2,5,7,6,9,0 ],其中最靠近原序列的是[ 2,5,7,0,6,9 ],我們可以觀察到: 在 7 後面排布的序列變成公升序序列後,該序列就是我們要找的那個。
那我們要對交換後的後半部分序列進行排序嗎,複雜度最好都是 o(nlogn)。大可不必,我們觀察到第三步得到的序列,交換前後 後半部分序列都必定是逆序排布的([ 9,7,0]、[9,6,0]),對原本逆序的序列求其公升序排列,只需要將其翻轉即可。
從後往前找到原序列的第乙個相鄰公升序對,得到其中較小的那個數字 i(也就是相鄰公升序對中靠前的那個數字);
從後往前找到第乙個比數字 i 大的數字 j ,交換兩者的位置;
交換後,對數字 j 後面的所有數字翻轉其位置。
如果遇到沒有相鄰公升序對的情況,直接翻轉所有數字位置,即可獲得最小序列。
public
void
nextpermutation
(int
nums)
//如果出現了順序對,則i會停在大於0的索引處
//當然,如果沒有出現順序對,則 i = -1,會對所有數字進行翻轉
if(i >=0)
//交換其位置,此後i+1到陣列末尾必定都是逆序的
swap
(nums, i, j);}
//將索引i之後的數字順序翻轉,使其成為乙個公升序的序列,達到值的最小
reverse
(nums, i +1)
;}private
void
reverse
(int
nums,
int start)
}private
void
swap
(int
nums,
int i,
int j)
LeetCode刷題筆記 31 下乙個排列
實現獲取下乙個排列的函式,演算法需要將給定數字序列重新排列成字典序中下乙個更大的排列。如果不存在下乙個更大的排列,則將數字重新排列成最小的排列 即公升序排列 必須原地修改,只允許使用額外常數空間。首先,我們觀察到對於任何給定序列的降序,沒有可能的下乙個更大的排列。9,5,4,3,1 我們需要從右邊找...
Leetcode刷題筆記
1.兩數之和給定乙個整數陣列nums 和乙個目標值target,請你在該陣列中找出和為目標值的那兩個整數,並返回他們的陣列下標。ps 你可以假設每種輸入只會對應乙個答案。但是,你不能重複利用這個陣列中同樣的元素。思路 用target減去nums中的每乙個數,並設立乙個字典來記錄對應的下標 class...
LeetCode刷題筆記
實現strstr 給定乙個 haystack 字串和乙個 needle 字串,在 haystack 字串中找出 needle 字串出現的第乙個位置 從0開始 如果不存在,則返回 1。示例 1 輸入 haystack hello needle ll 輸出 2 示例 2 輸入 haystack aaaa...