笔试题44. LeetCode OJ (31)

这个题目的意思结合所给示例以及题目描述,可以知道。给一个数组,求该数组所组成的数字的全排列的下一个数字,这句话不懂没关系,我举个例子你就懂了

例如:

1.若给的是 1 2 3 ,那么你要将数组内容变为 1 3 2;

2.若给的是 3 2 1 ,那么i要见数组的内容变为1 2 3;

其实这是一个循环的排列,就是你给任意的数字排列,都可以找到下一个排列,大概就是这样的情况

如上图,假如你给的数字是,123的全排列的中的一个,那么最后的结果将是这个排列的下一个排列,到这里相信大家理解意思了吧。那么下面就说说题目的解法吧:

1.首先题目不准使用额外的空间,如果可以的话,我们可以求出全排,然后像查表一样就可以了,不过仔细想想这样确实比较低效率,假若所给的数字为100位甚至更多,那么它的全排列将会是多大呢,将会使用很大的空间。

2.这个题目我想了比较长的时间,因为我一看到它的时候就知道,这其实是一个数学规律,只要找到规律了就好办了。我也测试了好几次,然后从错误中找到了规律。规律如下:

1.极端情况,如: 3 2 1

这种情况就可以直接将数组排序即可

2.最喜欢的情况: 1 2 3

这种情况只需要将2与3互换位置

3.平常且难想的情况: 假如给的数组序列为: 5 4 7 5 3 2

此时我们该如何动手呢?好了,这个时候就是展现真正本领的时候了....

请注意,上面的情况中5 4
7 5 3 2 序列中是蓝色的有序的,即依次降序,可以说明,这个时候5 4 7 5 3 2所组成的数字是最大的(绿色部分),所以下一步是找到比这个数字更大的数字,那么只能往前考虑了,即把4加入到 54 7 5 3 2 中,那么就是 5
4 7 5 3 2,意思就是找到比5 4 7 5 3 2大的数字中的最小的一个。用肉眼去看,是 5
5 2 3 4 7 所以我们是找到了比5
4 7 5 3 2 
大的数字中的最小的一个,方法是在黄色序列中(7 5 3 2)找到比红色(4)大的数字中最小的一个,然后互换两者的位置 5 57 4 3 2 ,还没完,此时还不是索要找的数字。将蓝色部分排序后 : 5
5 2 3 4 7,这就是慢要求的下一个数字。

到此我们可以开始系代码了,思路是,从后往前找,假设此时pos是最后一个位置,当我们找到pos-1位置比pos位置小的时候停止,那么这个时候pos位置以后的部分时有序的,如:

* 这个时候,再从右边的序列中找到比pos-1位置大的元素,交换两者,然后排序即可。

* 若pos指向 0 了,则说明该情况类似 3 2 1,我们将整个排序即可。

* 若pos的位置还是在最后一个,即 123 的情况,这儿时候交换pos和pos-1的位置即可。

代码:

class Solution {
public:
	void nextPermutation(vector<int>& nums)
	{
		int len = nums.size();
		if (len == 0 || len == 1)
		{
			return;
		}
		//从尾部向前找,找到nums[pos] > nums[pos-1]位置
		int pos = len - 1;
		while (pos > 0 && nums[pos] <= nums[pos - 1])
		{
			--pos;
		}

		if (pos == 0)
		{//说明到了最后一个位置,例如 3 2 1 ,此时将它排序即可
			sort(nums.begin(), nums.end());
			return;
		}
		else
		{
			if (pos == len - 1)
			{//pos 在最后一个位置,例如 1 2 3 ,那么此时将nums[pos]与nums[pos-1]互换即可
				swap(nums[pos], nums[pos - 1]);
				return;
			}
			else
			{ //这种情况说明pos在中间位置,举例吧,如:5 4 7 5 3 2
				int key = nums[pos - 1];
				//找比key值大的数字,即比4大的数,可以看到是5(后面的5)
				int begin = len - 1;
				while (begin > pos && nums[begin] <= key)
				{
					--begin;
				}
				//此时 begin 位置的数字比 key 值大,因为至少pos位置的数比key值大,而且从pos到len-1之间的数字是降序的
				swap(nums[pos - 1], nums[begin]);
				//swap以后序列为 5 5 7 4 3 2,然后从pos位置到len-1位置排序,即7~2排序
				sort(nums.begin() + pos, nums.end());
				return;
			}
		}
	}
};

相应的结果如下:

相信这个题带啊看懂了吧,如果还不明白的话,那么就得拿笔在纸上画画看吧。

时间: 2024-08-12 18:03:56

笔试题44. LeetCode OJ (31)的相关文章

笔试题57. LeetCode OJ (44)

这道题是一道类似正则表达式匹配的题目,但是我发现这个题的难度比之前那个题的难度高几个档次.如题目所示:'?'可以匹配任意一个字符,而 ' * ' 则可以匹配任意一个字符串,给你两个字符串,主串和模式串,判断他们是否可以匹配. 这道题的难度在于'*'的处理,到底'*'要和多少个字符串匹配呢?这个问题不好解决,我一开始的思路是: 1.遇到s[i] = p[i] || p[i] =='?' 这两种情况,两者都前进一位 2.遇到s[i] != p[i] 的时候,看前面是否有'*',若无则直接返回fals

笔试题28. LeetCode OJ (15)

这个题确实比较复杂,我刚刚开始的思路是先将数组排序,然后从左向右遍历,然后用两个变量lpos,rpos分别指向left+1 和 nums.size()-1,然后求三者的和,若和sum < 0 则让lpos加1,若sum>0则让rpos减1.想法不错,可是现实很残酷.这样 的解很容易错过真实解,我测试了很多遍,总有测试用例无法通过.其中还有一个时间复杂度太高了也没通过测试.这个题大家 可以自己去实现试试,真的错误点太多了,最后还是采用了比较老实的办法,再一步一步分析,求的解如下: class S

笔试题52. LeetCode OJ (39)

如果还记的话或者写过LeetCode的人会知道,这是nsum,已经不再是之前的twosum,threesum,foursum了.之前是都是使用 i 层循环解题的,那么现在n层循环理论上是可以解题的(其实应该不行),但是n是不确定了,而且是可变的,其变化范围是[1,n] 说道这里其实想说明的是,我们要换种思路去解题了.我在看到这个题的时候想到的思路是: 我们从小到大一个一个将最小的数字重复不断的加入到 vector 中,若vector现有的值的和比 target 大则将 vector 集合中的元素

笔试题63. LeetCode OJ (50)

这个题让我们自己实现一个 pow(x,y) 函数,看起来简简单单的一个函数,我相信绝对可以难倒一片人的,因为我们很难将它"写对".我之前其实也见过这个题的,在剑指offer上就出现过了,我感觉我写这个算法没有问题的,我考虑了很多方面而导致程序看起来比较的乱,最终修改了好几次才正确. 我个人感觉这个题比较重要的一点是 pow(x,y) 的功能的处理比凸显代码能力吧,首先比如: pow(3,10) 难道我们要使用循环10次的方法一个一个的乘吗?当然不能这样我给你个 pow(3,1000)

笔试题42. LeetCode OJ (29)

题目意思清晰明了:求两个数的商,不能使用乘法,除法或者求模运算等等.看似很简单的一道题,可是在排行榜上的正确率却是最低的一道,原因是情况很复杂,边界很难控制.需要考虑到的细节特别多,如:正负号,除数和被除数的取值,还有就是越界情况.其中越界情况最难考虑到,我也给拉低这道题的正确率增加了一份"功劳",真的测试了好几遍才将条件考虑全面,我的代码中写有很多注释(大部分以测试用例形式给出)可以帮助大家分析特定情况,这类型的题目没有很强的技巧,唯一需要注意的就是"细心".对了

笔试题73. LeetCode OJ (60)

Permutation Sequence 这个题是求1~n (n[1~9]) 的数字的全排列的第K个序列. 一般思路是:使用一个计数器,递归去找全排列序列,找到一个计数器加一,一直到第k个. 但是加若 n = 9 我要找的是第 (9! -1 )个数,那么上述办法的时间是多少,多半会超时的(没试过,但是我敢保证一定会超时的,因为这样的思路不可取),想一想我们只需要一个序列,并不必要把全部的序列都找出来吧.下面我给出一种解题方案,我个人感觉是可取的. 我们是学过数学的人,要我们求全排列的第 k 个序

笔试题85. LeetCode OJ (71)

              Simplify Path     这个题是给出一个字符串的相对路径,让我们返回绝对路径,让我们在Linux下自己去动手操作确实不难,可是用程序做起来的话确实比较麻烦. 我的解题思路是找好'/'和'.'之间的关系,找好他们之间的组合关系后这个题就容易一些.在路径中'.'和'/'的组合正常的可能只有'.'和'..'两种.'/'是起修饰作用的,说明当前目录下可能还存在目录. 既然我们要写这个题的话,那么肯定会出现各种组合的情况,其实我们只要处理好两种正常的情况就差不多了,

笔试题36. LeetCode OJ (23)

合并K个排序链表,没错.我的思路是分别从 K 个链表的中找出最小的一个值,然后依次插入链表,最后遍历完所有链表就好了,也没想中的那么难呀,循环遍历的思路如下: (先说明一下,它是不合格的) 主要思路是: 1.首先从所有排序链表里找一个最小val节点作为头结点 2.依次循环在各个链表里面找到最小节点摘下来尾插,循环结束的条件是当链表的数目为0或者为1的时候结束(可以通过lists[i]==NULL来判断lists[i]代表的链表是否结束了),还编写了一个函数用来找最小元素下标的,每次返回的list

笔试题30. LeetCode OJ (17)

这个题目有意思,和生活接近,题目的意思一看就知道,应该是字符串的全排列吧.但是需要注意的是有几数字字符是没有对应的字符串的,比如'0'和'1',所以我们的输入字符串中若有他们,则将它们过滤掉.这个题我的思路是递归,因为这种类型的题目递归思路清晰明了,若要使用循环,则会形成n层循环,所以循环的思想应该被淘汰掉.我在做这个题的时候喜欢先把"多余"的东西先给它解决掉,比如'0'和'1'这两个数字,我先遍历一边digits数组,将'0'和'1'过滤掉,这样在后面的递归中可以少考虑一些东西,自认