leetcode_31题——Next Permutation(STL)

下面摘抄的别人的讲解非常清楚

最近刷leetcode的时候遇见next permutation这道题,感觉挺有意思的一个题目,递归的方法是较简单并且容易想到的,在网上搜了其余的解法,就是std::next_permutation非递归解法,但是让人不是很舒服的就是关于原理的部分,千篇一律的都是摘抄《STL源码剖析》,也就是这样的。

在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。

想必有点C++功底的人都能看明白源码是这么个意思,但是这能算是原理么,这至多算是实现吧。相比之下老外就严谨多了,我找到了一篇文章,防止丢失,我保存在这里。http://blog.csdn.net/qq575787460/article/details/41206601,其中图片资源已经没了。看了这篇文章之后,我豁然开朗,在佩服老外严谨的态度之余,也把自己的理解纪律下来,希望能够帮助到一些人。

首先,关于什么是全排列不做解释。如果一个排列为A,下一个排列为A_NEXT,那么A_NEXT一定与A有尽可能长的公共前缀。

看具体例子,一个排列为124653,如何找到它的下一个排列,因为下一个排列一定与124653有尽可能长的前缀,所以,脑洞大开一下,从后面往前看这个序列,如果后面的若干个数字有下一个排列,问题就得到了解决。

第一步:找最后面1个数字的下一个全排列。

124653,显然最后1个数字3不具有下一个全排列。

第二步:找最后面2个数字的下一个全排列。

124653,显然最后2个数字53不具有下一个全排列。

第三步:找最后面3个数字的下一个全排列。

124653,显然最后3个数字653不具有下一个全排列。

------插曲:到这里相信大家已经看出来,如果一个序列是递减的,那么它不具有下一个排列。

第四步:找最后面4个数字的下一个全排列。

124653,我们发现显然最后4个数字4653具有下一个全排列。因为它不是递减的,例如6453,5643这些排列都在4653的后面。

我们总结上面的操作,并总结出重复上面操作的两种终止情况:

1:从后向前比较相邻的两个元素,直到前一个元素小于后一个元素,停止

2:如果已经没有了前一个元素,则说明这个排列是递减的,所以这个排列是没有下一个排列的。

124653这个排列终止情况是上面介绍的第一种,从后向前比较相邻的2个元素,遇到4<6的情况停止。

并且我们可以知道:

1:124653和它的下一个排列的公共前缀为12(因为4653存在下一个排列,所以前面的数字12保持不变)

2:4后面的元素是递减的(上面介绍的终止条件是前一个元素小于后一个元素,这里是4<6)

现在,我们开始考虑如何找到4653的下个排列,首先明确4后面的几个数字中至少有一个大于4.

4肯定要和653这3个数字中大于4的数字中(6,5)的某一个进行交换。这里就是4要和6,5中的某一个交换,很明显要和5交换,如果找到这样的元素呢,因为我们知道4后面的元素是递减的,所以在653中从后面往前查找,找到第一个大于4的数字,这就是需要和4进行交换的数字。这里我们找到了5,交换之后得到的临时序列为5643.,交换后得到的643也是一个递减序列。

所以得到的4653的下一个临时序列为5643,但是既然前面数字变大了(4653--->5643),后面的自然要变为升序才行,变换5643得到5346.

所以124653的下一个序列为125643.

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

/*
void nextPermutation(vector<int>& nums)
{
	vector<int>::iterator i1,i2;
	i1=nums.end()-2;
	i2=nums.end()-1;
	int flag=0;
	while(1)
	{
		if(*i1<*i2)
		{
			for(vector<int>::iterator i=nums.end()-1;i>=i2;i--)
			{
				if(*i>*i1)
				{int temp;temp=*i;*i=*i1;*i1=temp;break;}
			}
			for(vector<int>::iterator ik1=i2,ik2=nums.end()-1;ik2>=ik1;ik1++,ik2--)
			{
				int temp;
				temp=*ik1;
				*ik1=*ik2;
				*ik2=temp;
			}
			flag=1;
			break;
		}

		if(i1==nums.begin())
			break;
		i1--;
		i2--;
	}
	if(flag==0)
	{
		for(vector<int>::iterator ik1=nums.begin(),ik2=nums.end()-1;ik2>=ik1;ik1++,ik2--)
		{
			int temp;
			temp=*ik1;
			*ik1=*ik2;
			*ik2=temp;
		}
		return;
	}
	if(flag==1)
		return;
}
*/

void nextPermutation(vector<int>& nums)
{
	int len_nums=nums.size();
	int i1=len_nums-2;
	int i2=len_nums-1;
	int flag=0;
	while(1)
	{
		if(nums[i1]<nums[i2])
		{
			for(int i=len_nums-1;i>=i2;i--)
				if(nums[i]>nums[i1])
				{int temp;temp=nums[i1];nums[i1]=nums[i];nums[i]=temp;break;}
				for(int ik1=i2,ik2=len_nums-1;ik1<=ik2;ik1++,ik2--)
				{int temp;temp=nums[ik1];nums[ik1]=nums[ik2];nums[ik2]=temp;}
				flag=1;
				break;
		}
		if(i1==0)
			break;
		i1--;
		i2--;
	}
	if(flag==0)
		for(int ik1=0,ik2=len_nums-1;ik1<=ik2;ik1++,ik2--)
		{int temp;temp=nums[ik1];nums[ik1]=nums[ik2];nums[ik2]=temp;}
		return;
}

/*
void FanZhuan(vector<int>& nums,int i,int j)
{
	if(i==j)
		return;
	int len=j-i+1;
	int n=j;
	for(int m=i;m<=len/2+i;m++)
	{
		int temp;
		temp=nums[m];
		nums[m]=nums[n];
		nums[n]=temp;
		n--;
	}
	return;
}

void nextPermutation(vector<int>& nums)
{
	int len_nums=nums.size();
	int i1=len_nums-2;
	int i2=len_nums-1;
	int flag=0;
	while(1)
	{
		if(nums[i1]<nums[i2])
		{
			for(int i=len_nums-1;i>=i2;i--)
				if(nums[i]>nums[i1])
				{int temp;temp=nums[i1];nums[i1]=nums[i];nums[i]=temp;break;}
				FanZhuan(nums,i2,len_nums-1);
				flag=1;
				break;
		}
		if(i1==0)
			break;
		i1--;
		i2--;
	}
	if(flag==0)
		FanZhuan(nums,0,len_nums-1);
		return;
}
*/
int main()
{
	vector<int> vec;
	vec.push_back(1);vec.push_back(2);
	nextPermutation(vec);

	for(int i=0;i<vec.size();i++)
		cout<<vec[i]<<endl;

}

  

时间: 2024-12-19 13:45:42

leetcode_31题——Next Permutation(STL)的相关文章

乘风破浪:LeetCode真题_031_Next Permutation

乘风破浪:LeetCode真题_031_Next Permutation 一.前言 这是一道经典的题目,我们实在想不出最好的方法,只能按照已有的方法来解决,同时我们也应该思考一下为什么要这样做?是怎么想到的?这比我们记住步骤更加的有用. 二.Next Permutation 2.1 问题 2.2 分析与解决 排列(Arrangement),简单讲是从N个不同元素中取出M个,按照一定顺序排成一列,通常用A(M,N)表示.当M=N时,称为全排列(Permutation).从数学角度讲,全排列的个数A

leetcode第30题--Next Permutation

problem: 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

lintcode 容易题:Permutation Index 排列序号

题目: 排列序号 给出一个不含重复数字的排列,求这些数字的所有排列按字典序排序后该排列的编号.其中,编号从1开始. 样例 例如,排列[1,2,4]是第1个排列. 解题: 这个题目感觉很坑的.感觉这只有求出所有的排列,然后找出其对应的下标,但是怎么求出排列,在做Project Euler 时候碰到过,但是现在我又不会写了,那时候毕竟是抄别人的程序的.在geekviewpoint看到一种很厉害的解法,不需要求所有的排列,直接根据给的数组进行求解. 思路: 1.对于四位数:4213 = 4*100+2

CCF 第六次计算机职业认证 第四题 收货 stl动态存储和fleury算法的综合应用

问题描述 为了增加公司收入,F公司新开设了物流业务.由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道.然而,F公司现在只安排了小明一个人负责所有街道的服务. 任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案.城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的首尾都正好连接着一个交叉路口.除开街道的首尾端点,街道不会在其他位置与其他街道相交.每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一条或两条街

【LeetCode每天一题】Permutation Sequence(排列序列)

The set [1,2,3,...,n] contains a total of n! unique permutations.By listing and labeling all of the permutations in order, we get the following sequence for n = 3: "123" "132" "213" "231" "312" "321&q

【NOIP模拟题】Permutation(dp+高精度)

首先我们可以这样想: 设状态f[i, j]表示1-i序列有j个'<'的方案数 那么考虑转移 因为i比i-1大,所以可以考虑从i-1来转移.首先i是要插入1-i-1这个序列的,所以我们可以思考插入的位置: 仔细推下可得: 当插入的位置原来是‘<'时,答案不会改变 当插入的位置原来是'>'时,答案会+1 当插入左边界时,答案不变 当插入有边界时,答案+1 那么我们知道了前i-1的'<'数量和'>'的数量那么就能转移了 f[i,j]=(j+1)*f[i-1, j]+(max{i-1

11月刷题总结

这是11月的坑...现在来填... noip考跪...希望省选rp++ (11月刷了不少水题... 动态规划+递推: [BZOJ]1072: [SCOI2007]排列perm(状压dp+特殊的技巧) [BZOJ]1068: [SCOI2007]压缩(dp) [BZOJ]1088: [SCOI2005]扫雷Mine(递推) [BZOJ]1096: [ZJOI2007]仓库建设(dp+斜率优化) [BZOJ]1037: [ZJOI2008]生日聚会Party(递推+特殊的技巧) [BZOJ]1009

审题习惯 &amp;&amp; debug习惯

做题习惯 静态查错一遍后再测样例 读double型的变量尽量用scanf (int)r * 1000 应写成(int) (r * 1000) 开新题之前,检查这一题的输出格式/数据范围会不会爆long long 对于极端"小数据" 矩阵乘法的时候注意考虑初始化的那几个值,特判输出. 对于取模 做了减法之后取模一定要while(ans<0)ans+=mod; 你读入一个数,若它已经超过模数,直接模!别回头!,ksm的a和k都是可以直接模的 题目要求模一个数的时候看清楚模的是不是质数

Subsets II [leetcode] 从获取子集的递归和循环方法说起,解决重复子集的问题

这一题和Permutation II很像,一个是排列一个是组合. 我们理清思路,从最基本的获取子集的方法开始分析: 获取子集总的来说可以用循环或者递归做,同时还可以根据数字对应的binary code得到. 例如s = {x,y,z}可以生成的组合有:x,y,z,xy,yz,xz,xyz,0 第一种思路: 1. 维护一个集合Set(i),包含s[0...i]可生成的所有组合 s[0...i+1]可以生成的所有组合为:Set(i) + (Set(i)+s[i+1]) void permutatio