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

大概意思是:

123的全排列按字典顺序为:

    123 132 213 231 312 321

    如果输入其中某一个序列,返回它的下一个序列。如:输入:213 输出:231 ;输入:321 输出:123

数学推导:

下面归纳分析该过程。假设一个有m个元素的序列pn,其下一个较大序列为pn+1

1) 若pn最右端的2个元素构成一个增序子序列,那么直接反转这2个元素使该子序列成为减序,即可得到pn+1

2) 若pn最右端一共有连续的s个元素构成一个减序子序列,令i = m - s,则有pn(i) < pn(i+1),其中pn(i)表示排列pn的第i个元素。例如pn=<1 2 5 4 3>,那么pn的右端最多有3个元素构成一个减序子集<5 4 3>,i=5-3=2,则有pn(i)=2 < 5=pn(i+1)。因此若将pn(i)和其右边的子集s {pn(i+1), pn(i+2), ..., pn(m)}中任意一个元素调换必能得到一个较大的序列(不一定是下一个)。要保证是下一个较大的序列,必须保持pn(i)左边的元素不动,并在子集s {pn(i+1), pn(i+2), ..., pn(m)}中找出所有比pn(i)大的元素中最小的一个pn(j),即不存在pn(k) ∈ s且pn(i) < pn(k) < pn(j),然后将二者调换位置。现在只要使新子集{pn(i+1), pn(i+2), ..., pn(i), ...,pn(m)}成为最小序列即得到pn+1。注意到新子集仍保持减序,那么此时直接将其反转即可得到pn+1 {pn(1), pn(2), ..., pn(j), pn(m), pn(m-1), ..., pn(i), ..., pn(i+2), pn(i+1)}。

    

算法思想:举例如下

    输入:1 4 6 5 3 2

    step1:从右往左找到第一个破坏升序(非严格)的元素,此例中为4.记下标为 i

    step2: 依然从右往左,找到第一个大于4的元素,此例中5,交换4和5.

    step3:从i+1到最右端,逆置。6 4 3 2 to 2 3 4 6

    1 5 2 3 4 6 即为所求。

public class Solution {
    public void nextPermutation(int[] nums) {
       	if (nums.length == 0) {
			return ;
		}
	 int i = nums.length-1;
	 int j ;
	//1.从右向左找到第一个破坏升序排列的元素,找到其下标,下标为i-1.
	 while (i > 0 && nums[i] <= nums[i-1]) {
		i--;
	}
	 if (i != 0) {
		j = nums.length - 1;
		//2.依然从右往左,找到第一个大于nums[i-1]的元素,交换这两个元素.
		while (nums[j] <= nums[i-1]) {
			j--;
		}
		swap(nums,j,i-1);
	}
	 j = nums.length-1;
	while (i< j){	
		swap(nums, i,j);		
		i++; j--;		
		}
    }
   public void swap(int[] nums,int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
}


这个题其实明白其中的原理就不难,自己做的时候找第一个破坏升序元素那的下标总是发蒙,应该多熟练下,

下面是leetcode上参考的答案,写的比我的看着舒服些。

public class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i + 1] <= nums[i]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[j] <= nums[i]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    private void reverse(int[] nums, int start) {
        int i = start, j = nums.length - 1;
        while (i < j) {
            swap(nums, i, j);
            i++;
            j--;
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值