LeetCode 第31题 下一个排列

(一)题目描述

  实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

  如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

  必须原地修改,只允许使用额外常数空间。

  以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
  1,2,3 → 1,3,2
  3,2,1 → 1,2,3
  1,1,5 → 1,5,1

 

  


 

(二)算法思路

  首先解释一下什么是字典序:

  设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
  1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}
  2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
  3)对换pj,pk
  4)再将pj+1......pk-1pkpk+1......pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个排列。
 
  解法:
  解法一:我们可以把所有的排序全部列出来,然后找到下一排列,但是这样的算法效率太低,LeetCode肯定不能通过.但是这也是最简单和最容易想到的方法了.
 
  解法二:一遍扫描法
  1. 我们直接从后往前扫描,先把最后一位当做基准,
  2. 看倒数第二位比倒数第一位大还是小,如果比倒数第一位大,呢就把倒数二位当做基准,直到找到比它小的一位数,我们将其记为 a.
  3. 然后用这位数去和它之后的数进行比较,找到比它大的数中最小的一位b.
  4. 然后交换a和b的位置
  5. 再将a之后的数字逆序排列,就是最终的结果.

   我觉得自己已经解释的很清楚了,但是为了大家更好的去理解这个过程,下面请看一张动图,就能更加清晰的掌握这个过程了.(图是借鉴领扣的)

  Next Permutation


 

(三)LeetCode   AC代码

  

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

 

 

 虽然不是很难,但是自己还是搞了很久.

   自己将其总结下来,相信慢慢的自己会有思路去写算法.


 

 

     

 

 

 

posted @ 2018-11-11 16:34  朝才  阅读(1974)  评论(0编辑  收藏  举报