张伦聪的技术博客 Research And Development

31. 下一个排列

2018-04-27

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

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

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

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

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

解:解这题首先要知道什么是全排列?

全排列:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。公式:全排列数f(n)=n!(定义0!=1)。

这里以A{a,b,c}为例,来说明全排列的生成方法,对于这个集合,其包含3个元素,所有的排列情况有3!=6种,对于每一种排列,其第一个元素有3种选择a,b,c,对于第一个元素为a的排列,其第二个元素有2种选择b,c;第一个元素为b的排列,第二个元素也有2种选择a,c,……,依次类推,我们可以将集合的全排列与一棵多叉树对应。如下图所示

屁话太多,例如使a=1,b=2,c=3,那么abc的全排列如下:

1, 2, 3

1, 3, 2

2, 1, 3

2, 3, 1

3, 1, 2

3, 2, 1

解题思路: 这里我们以1  2  7  4  3  1 → 1  3  1  2  4  7为例,为什么127431的下一个更大排列是131247呢?其实我们可以看做求这几个数字组合中下一个比127431大的整数是什么?!计算步骤

  • 首先从数组尾nums.length-1往前遍历到0,找到一个nums[i+]>nums[i]的标志位i
  • 再从数组尾nums.length-1往前遍历到i,找到一个nums[j]>nums[i]的标志位j
  • 交换下标i和j的数字
  • 反转数组i+1~nums.length-1

1  2  7  4  3  1

1  2  7  4  3  1

1  3  7  4  2  1

1  3  1  2  4  7

    public void nextPermutation(int[] nums) {
        for(int i=nums.length-2;i>=0;i--){
            if(nums[i+1]>nums[i]){
                for(int j=nums.length-1;j>i;j--){
                    if(nums[j]>nums[i]){
                        swap(nums,i,j);
                        reverse(nums,i+1,nums.length-1);
                        return;
                    }
                }
            }
        }
        reverse(nums,0,nums.length-1);
    }
    private void swap(int[] nums,int left,int right){
        int tmp=nums[left];
        nums[left]=nums[right];
        nums[right]=tmp;
    }
    private void reverse(int[] nums,int left,int right){
        while(left<right){
            int tmp=nums[left];
            nums[left]=nums[right];
            nums[right]=tmp;
            left++;
            right--;
        }
    }

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏博主

类似文章

上一篇 18. 四数之和

留言