LeetCode Next Permutation

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.

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


思路分析:这是一道经典面试题,求某个排列按照字典顺序的下一个排列,基本是一道数学推理题,O(N)的解法如下,以7 8 6 9 8 7 2为例

假设数组大小为 n
          1.从后往前,找到第一个满足 A[i-1] < A[i]的数, 例子中就是找到6,可以看到A[i]到A[n-1]这些都是单调递减序列。
          2.从后向前,从 A[n-1]到A[i]中找到第一个比A[i-1]大的数,例子中就是7(也就是说在A[n-1]到A[i]的值中找到比A[i-1]大的集合中的最小的一个值)
          3.交换这两个值(例子中就是6和7),并且把A[i+1]到A[n-1]排序,从小到大。
          实例:7 8 6 9 8 7 2
                      7 8 7 9 8 6 2
                      7 8 7 2 6 8 9
                理解说明:怎么求7 8 6 9 8 7 2的下一个字典序排列呢?可以从后向前看,发现9 8 7 2已经是递减(可以不严格,比如中间出现两数相等),这就是说,9 8 7 2 已经是这四个数组成的全排列中的最后一个(最“小”的一个)所以应该要变化前面的6了,但是应该和谁交换呢?我们于是再次从后向前找到比6大的最“接近”的数,于是我们找到7,然后交换6和7,于是前面三位从786变成了787,后面的四个数我们希望生成最靠前的那个全排列,于是把7后面的数递增排列得到2 6 8 9,和前面的7 8 7拼成了7 8 7 2 6 8 9,就是下一个字典序排列。下面的图形象解释的交换数的过程,来源于http://blog.csdn.net/m6830098/article/details/17291259


AC Code

public class Solution {
    public void nextPermutation(int[] num) {
          /*O(n)解法 数学推理题
          假设数组大小为 n
          1.从后往前,找到第一个 A[i-1] < A[i]的, 例子中就是找到6,可以看到A[i]到A[n-1]这些都是单调递减序列。
          2.从后向前,从 A[n-1]到A[i]中找到第一个比A[i-1]大的值7(也就是说在A[n-1]到A[i]的值中找到比A[i-1]大的集合中的最小的一个值)
          3.交换这两个值(例子中就是6和7),并且把A[i+1]到A[n-1]排序,从小到大。
          实例:7 8 6 9 8 7 2
                7 8 7 9 8 6 2
                7 8 7 2 6 8 9
                理解说明:怎么求7 8 6 9 8 7 2的下一个全排列呢?可以从后向前看,发现9 8 7 2已经是递减(可以不严格,比如中间出现两数相等),这就是说,9 8 7 2 已经是这四个数组成的全排列中的最后一个(最小的一个)所以应该要变化前面的6了,但是应该和谁交换呢?我们于是再次从后向前找到比6大的最“接近”的数,于是我们找到7,然后交换6和7,于是前面三位从786变成了787,后面的四个数我们希望生成最靠前的那个全排列,于是把7后面的数递增排列得到2 6 8 9,和前面的7 8 7拼成了7 8 7 2 6 8 9,就是下一个全排列
          */
          if(num == null || num.length <= 1) return;
          int i = num.length - 2;
          while(i >= 0 && num[i] >= num[i+1]){
              i--;
          }
          if(i == -1){
              reverse(num, 0, num.length - 1);
          }
          if(i >= 0) {
              int k = num.length - 1;
              while(k > i && num[k] <= num[i]){
                  k--;
              }
              swap(num, i, k);
              reverse(num, i+1, num.length - 1);
          }
    }
    
    public void swap(int[] num, int i, int j){
        int temp = num[i];
        num[i] = num[j];
        num[j] = temp;
    }
    
    public void reverse(int[] num, int i, int j){
        while(i < j){
            swap(num, i++, j--);
        }
    }
}

http://blog.csdn.net/m6830098/article/details/17291259

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值