31. Next Permutation

这道题思路如下:

1.从后往前找到第一个不是递增的数字的位置,记录下为p,如果p已经走到尽头,那么直接颠倒所有数字然后返回

2.从p往后找到比p大的最小的那个数的位置q

3.交换p,q的位置

4.对于p之后的所有的数颠倒位置

 

理由是这样的,如果一个数从后往前的数字都是递增的,那么这个数已经是排列出来的最大值了。

所以,我们现在的目标就是找到不是递增的那个最小的一位的数字x,这个数字是我们将要替换的。

因为到这个数字之后的数字,我们都已经遍历过了,是一个递减的数列,所以我们找到挨的最近的那个比x大最少的那个数字把x给替换掉,这样,就实现了把x换成了比x大的最小的数字,整个数字就变大了。

然后又是因为后面的数字是递增的,所以我们替换过去的位置也是排列好的,把颠倒就行了。

比如code ganker举得例子:2,3,6,5,4,1。

从后往前找到第一个不是递增的,也就是3这个位置。6541已经是这几个数字可以组成的最大的数字了,没有什么可以改进的地方,而3是可以改变的最低位,所以从3开始。6541已经是排序好的,所以我们要找到离3最近的,但是又比3大的数,也就是4。交换了3,4的位置,数字变成2,4,6,5,3,1。因为3取代的位置是,比3大的最小的数的位置,所以6531也是排列好的,也是这几个数字可以组成的最大数了。

由于高位被替换过了,也就是3被替换成4了,所以后面的数需要是可能的最小排列,而后面的数又是倒叙排过的,所以翻转过来就行。

代码如下:

 1 public void nextPermutation(int[] nums) {
 2         if(nums == null || nums.length <= 1) {
 3             return;
 4         }
 5         int i = nums.length - 1;
 6         while(i > 0 && nums[i-1] >= nums[i]) {
 7             i--;
 8         }
 9         i--;
10         if(i == -1) {
11             reverse(nums, 0, nums.length - 1);
12             return;
13         }
14         int j = i+1;
15         while(j < nums.length && nums[j] > nums[i]){
16             j++;
17         }
18         j--;
19         int temp = nums[i];
20         nums[i] = nums[j];
21         nums[j] = temp;
22         reverse(nums, i+1, nums.length - 1);
23         return;
24     }
25     
26     private int[] reverse(int[] nums, int start, int end) {
27         int temp = nums[start];
28         while(start < end) {
29             temp = nums[start];
30             nums[start] = nums[end];
31             nums[end] = temp;
32             start++;
33             end--;
34         }
35         return nums;
36     }

bug记录:

这个题目居然明明懂了原理,却错到我要吐…………每一行都是蠢人的血泪

1. 当length小于等于1的时候不需要处理

2. …………太多了算了= =!下次要注意就是了

 

posted @ 2016-02-26 08:53  warmland  阅读(345)  评论(0编辑  收藏  举报