31 Next Permutation

题目链接:https://leetcode.com/problems/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,31,3,2
3,2,11,2,3
1,1,51,5,1

解题思路:
这题主要侧重数学技巧。把数组看做一个数字,尽量使数字在低位部分的元素变大来增大数字的大小。

举例:                 4,2,0,2,3,2,0
交换 2,3:            4,2,0,3,2,2,0
对 3 以后的数字排序:    4,2,0,3,0,2,2
  1. 数组从后往前遍历
  2. 数字2比它后面的每一位都大,所以它换到哪一位上都比原来的数字小。
  3. 数字 3 同理。
  4. 数字 2 后面存在大于它的数字 3(3 是 大于 2 的数字中最小的),它们俩交换后能增大原本的数字。为了使增大的数字最小,要使 3 后的数字变为递增排列。

代码总结
1. 从数组倒数第二个数开始,逆序遍历数组元素(外层循环)
2. 对每一个被遍历的元素来说,用它和它后面的元素依次做比较(内层循环)
3. 如果存在比它大的元素集合,则选出集合中最小的那个元素和它交换位置,然后再对被遍历的下标之后的元素进行排序(升序)

public class Solution {
    public void nextPermutation(int[] nums) {
        if(nums == null || nums.length == 0)
            return;
        int len = nums.length;
        for(int i = len - 2; i >= 0; i --) {
            int min = Integer.MAX_VALUE;
            int k = -1;
            for(int j = len - 1; j > i; j --) {
                if(nums[i] < nums[j] && nums[j] < min) {
                    k = j;
                    min = nums[j];
                }
            }
            if(k != -1) {
                int temp = nums[k];
                nums[k] = nums[i];
                nums[i] = temp;
                Arrays.sort(nums, i + 1, len);
                return;
            }
        }
        for(int i = 0; i < len / 2; i ++) {
            int temp = nums[i];
            nums[i] = nums[len - 1 - i];
            nums[len - 1 - i] =  temp;
        }
        return;
    }
}
265 / 265 test cases passed.
Status: Accepted
Runtime: 348 ms

另一种解法,也算是对上面解法的优化。
参考链接:http://blog.csdn.net/linhuanmars/article/details/20434115

这道题是给定一个数组和一个排列,求下一个排列。算法上其实没有什么特别的地方,主要的问题是经常不是一见到这个题就能马上理清思路。
下面我们用一个例子来说明,比如排列是(2,3,6,5,4,1),求下一个排列的基本步骤是这样:

  1. 先从后往前找到第一个不是依次增长的数,记录下位置p。比如例子中的3,对应的位置是1;
  2. 接下来分两种情况:
    1. 如果上面的数字都是依次增长的,那么说明这是最后一个排列,下一个就是第一个,其实把所有数字反转过来即可(比如(6,5,4,3,2,1)下一个是(1,2,3,4,5,6));
    2. 否则,如果p存在,从p开始往后找,找到下一个数就比p对应的数小的数字,然后两个调换位置,比如例子中的4。调换位置后得到(2,4,6,5,3,1)。最后把p之后的所有数字倒序,比如例子中得到(2,4,1,3,5,6), 这个即是要求的下一个排列。

以上方法中,最坏情况需要扫描数组三次,所以时间复杂度是O(3*n)=O(n),空间复杂度是O(1)。

根据这个思路,自己重新写了代码:

public class Solution {
    public void nextPermutation(int[] nums) {
        if(nums == null || nums.length == 0)
            return;
        int len = nums.length;
        for(int i = len - 1; i >= 0; i --) {
            if(i - 1 >= 0 && nums[i - 1] < nums[i]) {
                int k = i;
                for(int j = i + 1; j < len; j ++) {
                    if(nums[i - 1] < nums[j])
                        k = j;
                }
                int temp = nums[k];
                nums[k] = nums[i - 1];
                nums[i - 1] = temp;
                Arrays.sort(nums, i, len);
                return;
            }
        }
        for(int i = 0; i < len / 2; i ++) {
            int temp = nums[i];
            nums[i] = nums[len - 1 - i];
            nums[len - 1 - i] =  temp;
        }
        return;
    }
}
265 / 265 test cases passed.
Status: Accepted
Runtime: 328 ms
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值