Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.git
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column. 1,2,3 → 1,3,2 3,2,1 → 1,2,3 1,1,5 → 1,5,1
難度:中
分析:這裏須要跟你們介紹一下相關的幾個概念:github
排列(Arrangement),簡單講是從N個不一樣元素中取出M個,按照必定順序排成一列,一般用A(M,N)表示。當M=N時,稱爲全排列(Permutation)。
例如對於一個集合A={1,2,3},首先獲取全排列a1: 1,2,3;而後獲取下一個排列a2: 1,3,2;
按此順序,A的全排列以下,共6種:
a1: 1,2,3; a2: 1,3,2; a3: 2,1,3; a4: 2,3,1; a5: 3,1,2; a6: 3,2,1;
從數學角度講,全排列的個數A(N,N)=(N)*(N-1)*...*2*1=N!,但從編程角度,如何獲取全部排列?那麼就必須按照某種順序逐個得到下一個排列,一般按照升序順序(字典序lexicographically)得到下一個排列。
對於給定的任意一種全排列,若是能求出下一個全排列的狀況,那麼求得全部全排列狀況就容易了,也就是題目要求實現的下一個全排列算法(Next Permutation)。算法
思路:
設目前有一個集合的一種全排列狀況A : 1,5,8,4,7,6,5,3,1,求取下一個排列的步驟以下:編程
/** Tips: next permuation based on the ascending order sort * sketch : * current: 1 5 8 4 7 6 5 3 1 * | | | * find i----+ j +----end * swap i and j : * 1 5 8 5 7 6 4 3 1 * | | | * j----+ i +----end * reverse j+1 to end : * 1 5 8 5 1 3 4 6 7 * | | * find j----+ +----end * */
具體方法爲:
a)從後向前查找第一個相鄰元素對(i,i+1),而且知足A[i] < A[i+1]。
易知,此時從j到end必然是降序。能夠用反證法證實,請自行證實。
b)在[i+1,end)中尋找一個最小的j使其知足A[i]<A[j]。
因爲[j,end)是降序的,因此必然存在一個j知足上面條件;而且能夠從後向前查找第一個知足A[i]<A[j]關係的j,此時的j必是待找的j。
c)將i與j交換。
此時,i處變成比i大的最小元素,由於下一個全排列必須是與當前排列按照升序排序相鄰的排列,故選擇最小的元素替代i。
易知,交換後的[j,end)仍然知足降序排序。
d)逆置[j,end)
因爲此時[j,end)是降序的,故將其逆置。最終得到下一全排序。
注意:若是在步驟a)找不到符合的相鄰元素對,即此時i=begin,則說明當前[begin,end)爲一個降序順序,即無下一個全排列,因而將其逆置成升序。
post
public void NextPermutation(int[] nums) { int i = nums.Length - 2; //末尾向前查找,找到第一個i,使得A[i] < A[i+1] while (i >= 0 && nums[i + 1] <= nums[i]) { i--; } if (i >= 0) { //從i下標向後找第一個j,使得A[i]<A[j] int j = nums.Length - 1; while (j >= 0 && nums[j] <= nums[i]) { j--; } //交換i,j Swap(nums, i, j); } //逆置j以後的元素 Reverse(nums, i + 1, nums.Length); } //逆置排序 private void Reverse(int[] nums, int start, int end) { int i = start, j = end - 1; while (i < j) { Swap(nums, i, j); i++; j--; } } //交換 private void Swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }