給出一個數組,從新排列,返回『下一個排列,題目的描述中還給出了幾個例子。數組
有一首歌名是下一個天亮,不過和這道題沒什麼關係。還有一類題是已有一堆數字要返回全部的排列方式,和這道題也沒什麼關係。按照題目的描述中的例子,好比:[1,2,3]
-> [1,3,2]
觀察了一下,是交換了2和3的位置。[3,2,1]
-> [1,2,3]
這個就是整個數組的逆序排列。
根據這兩個例子猜想,須要兩個輔助的方法,一個是交換(swap),另外一個是逆序(reverse)。
繼續看,交換的地方應該是相鄰兩個數字後一個比前一個大的狀況,並且靠後的優先,好比[#$%,1,2,3]
返回的也是[#$%,1,3,2]
。因此第一步的思路就是從後往前找,找一對兒符合要求的相鄰數字。若是找到頭都沒找到,那能夠直接逆序輸出返回結果了。
找到這對兒以後,小的數字確定要交換到後面的,先設定這個小數字的位置是first。而後要交換的數字是first後面比它大的裏面最小的,就是貼着頭皮理髮的感受。交換過來以後,再把first後面的部分逆序輸出就行了。
這道題的關鍵在於,找到規律,數學上的規律。關鍵的關鍵在於,找不到規律就看discussion吧。code
public class Solution { public void nextPermutation(int[] nums) { //排除corner case if(nums == null || nums.length < 2) return; //找那對兒數字 int right = nums.length-1; while(right > 0){ if(nums[right-1] < nums[right]){ break; } right--; } //沒找着符合要求的狀況,直接reverse。 if(right == 0){ reverse(nums, 0, nums.length-1); return; } int first = right-1; int nextBig = right; while(right < nums.length){ //要大,還不能太大。 if(nums[right] <= nums[nextBig] && nums[right] > nums[first]){ nextBig = right; } right++; } swap(nums, first, nextBig); reverse(nums, first+1, nums.length-1); } private void swap(int[] nums, int first, int second){ int temp = nums[first]; nums[first] = nums[second]; nums[second] = temp; return; } private void reverse(int[] nums,int start, int end){ while(start < end){ int temp = nums[start]; nums[start] = nums[end]; nums[end] = temp; start++; end--; } } }
這個很顯然是O(n)了,第一遍找一對兒數字的時候掃了一遍,而後第二次再找nextBig的時候又掃了一遍,最後逆序輸出,掃了好幾回,最後依然是O(n)。leetcode