Algorithm之路三十一:Next Permutation

本文介绍了一种算法,用于找出整数数组的下一个字典序排列,包括实现思路与代码示例。

题目:

给出一个数组,默认为int型,现需求出数组内元素按照字典序排列的下一个排列,说白了就是说找出数组内的元素可以组成一个序列,这个序列刚刚好比原序列大,要求inplace调整。如果原排列就是最大的排列,那么返回最小的排列,这样听起来太绕了,看下例子应该就懂了。

举例:

1,2,3    ---->    1,3,2原因是1,2,3可以组成的顺序有123,132,213,231,312,321,其中刚好比123大的就是132

3,2,1    ---->    1,2,3因为321是1,2,3三个数的所有排列中最大的那个,所以应将数组调整为123,最小的排列。

按照题目的要求,以上的排列的大小的比较标准都应该按照字典序,比如1,10,110,2,3这样的,但是由于在submit之前没有想到这个事情,直接将大小的比较标准按数字的大小进行,之后才想起来,但是已经通过了,所有也就没有再管,谁知道oj判断条件和它本身的题目的意思是不是相同的呢,或者是我理解错题目中的lexicographically next greater permutation意思了。

思路:

看一个例子,14765321,仅仅比它大的排列是15123467,我们做的操作是将第二位的4和第五位的5调换了一下位置,然后将后六位的顺序逆置了以下。再看一个例子,17654312,仅仅比它大的排列是17654321,我们做的操作是将倒数第二位的2和倒数第一位的1调换了一下位置。7654321,不存在仅仅比它大的例子,所以我们的结果应该是将这个数逆置为1234567。从上面的例子加上自己测试的其他例子,可以总结出如何得到一个仅仅比当前排列大的排列的方法:首先从后往前找,找到第一组满足nums[i+1]>nums[i]大的i,然后在i-nums.length之间找到一个数nums[j]满足j>i,且nums[j]>nums[i],nums[j+1]<nums[i],然后调换nums[i]和nums[j],然后将i-nums.length之间的数逆置即可。如果j不存在,那么不做调换操作,如果i不存在,那么直接做逆置操作。

代码:

#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
void nextPermutation(vector<int>& nums)
{
	int length = nums.size();
	if(length == 1 || length == 0) return;
	int i,j,temp;
	for(i = length - 2;i >= 0;i--)
		if(nums[i + 1] > nums[i]) break;
	if(i >= 0)
	{
		for(j = length - 1;j > i;j--)
			if(nums[j]>nums[i]) break;
		temp = nums[i];nums[i] = nums[j];nums[j] = temp;
	}
	j = length - 1;
	i++;
	while(i < j)
	{
		temp = nums[i];nums[i] = nums[j];nums[j] = temp;
		i++;j--;		
	}
}
int main()
{
	vector<int> nums;
	nums.push_back(1);
	nums.push_back(5);
	nums.push_back(8);
	nums.push_back(4);
	nums.push_back(7);
	nums.push_back(6);
	nums.push_back(5);
	nums.push_back(3);
	nums.push_back(1);
	nextPermutation(nums);
	cout<<nums[0]<<endl;
	cout<<nums[1]<<endl;
	cout<<nums[2]<<endl;
	cout<<nums[3]<<endl;
	cout<<nums[4]<<endl;
	cout<<nums[5]<<endl;
	cout<<nums[6]<<endl;
	cout<<nums[7]<<endl;
	cout<<nums[8]<<endl;
	return 0;
}

时间复杂度:

具体的运行时间和测试数据有很大的关系,这里只分析一个最坏情况,最坏情况下,找i需要pass一次数组,找j需要pass一次数组,逆置i-nums.length部分的序列需要经过nums.length/2的长度,设n = nums.length,所以最坏情况下时间复杂度为O(2.5n)。

空间复杂度:

O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值