笔试题54. LeetCode OJ (41)

这个题是找出无序数组里面的第一个不连续的正整数,而且时间复杂度不超过O(n)。首先分析一下:数组是无序的,需要找出第一个不连续的数字,而排序的算法一般很难达到O(n)的时间复杂度。这个时候我们必须得明白一种做法:空间换取时间的做法,我首先想到的是位图即bitmap(STL中交bitset),位图可以节约空间,而且可以判断出数字是否出现,真的是比较理想的数据结构。于是我就在函数中使用了bitset:

const int N = nums.size();
bitset<N> BitSet;

我发现这条语句在类里面行不通,在C++中const 修饰的变量是具有常性的,可是在函数体内使用时却行不通,真的是太可惜了,自己去实现一个bitmap又显得累赘,于是我决定放弃使用bitmap(这并不代表bitmap不行)。既然题目给我们的是一个vector,那我就使用一个vector当做bitmap,虽然空间上低效了很多(这会儿才想起来vector<char>这样的vector能够节约一些空间),但是应该不会产生很大的影响吧,于是我就使用了:

size_t len = nums.size();
vector<int> v;
v.resize(len);

细心的人肯定会说,万一nums里面的数字很大呢,你的数组的下标根本不能达到那么大,这样赋值的时候就会导致程序崩溃呀,其实我们有些事情没必要做,我的思路是这样的,nums数组里面的数字在 [0 , len] 范围内我们就将新vector相应下标置为1,若超过了的我们直接跳过,跳过岂不是思维不严谨啊。我想说的,我的vector大小和数组nums的大小一样大,就算nums是所有元素都是正的且有序的,我们能全部装下,若是无序的,第一个断开的地方肯定会在中间,绝对不会超出了数组的范围,所以不会存在上面所说的情况的,请看代码吧:

class Solution {
public:
	int firstMissingPositive(vector<int>& nums)
	{
	    //这个题用位图或者哈希表都可以,不过使用bitset不是很方便,其大小决定不了,我还是开辟了nums.size()+1 大小的数组,若是连续全部都可以放下,不连续的话肯定会在中间断开的,没必要全部统计位置了
		const size_t len = nums.size();
		vector<int> tmp;
		tmp.resize(len + 1);
		for (size_t i = 0; i < len; ++i)
		{
			if (nums[i] > 0 && nums[i] <= len)
			{
				tmp[nums[i]] = 1;
			}
		}

		for (size_t i = 1; i < len + 1; ++i)
		{
			if (tmp[i] == 0)
			{
				return i;
			}
		}

		return len + 1;
	}
};

结果:

时间: 2024-11-04 14:03:52

笔试题54. LeetCode OJ (41)的相关文章

笔试题28. LeetCode OJ (15)

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

笔试题44. LeetCode OJ (31)

这个题目的意思结合所给示例以及题目描述,可以知道.给一个数组,求该数组所组成的数字的全排列的下一个数字,这句话不懂没关系,我举个例子你就懂了 例如: 1.若给的是 1 2 3 ,那么你要将数组内容变为 1 3 2: 2.若给的是 3 2 1 ,那么i要见数组的内容变为1 2 3: 其实这是一个循环的排列,就是你给任意的数字排列,都可以找到下一个排列,大概就是这样的情况 如上图,假如你给的数字是,123的全排列的中的一个,那么最后的结果将是这个排列的下一个排列,到这里相信大家理解意思了吧.那么下面

笔试题52. LeetCode OJ (39)

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

笔试题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'过滤掉,这样在后面的递归中可以少考虑一些东西,自认

笔试题74. LeetCode OJ (61)

    Rotate List    这个题的意思旋转链表,更具体点的意思右移链表,移出去的节点放到头部前面,结合着题目给出的例子还是很好理解的. 这个题的主要思路是:摘取从末尾到头的k个节点,然后将他们放到头部. 需要注意的是,上面说的k并不一定等于传入的k的值,因为这个k很可能比链表的长度还大.所以我主要思路是:遍历一遍链表,找到链表的长度n,然后k%=n(这时候k<n,我们更喜欢的是此时k=0),这样就可以找出实际需要移动的节点的个数,然后将链表的最后k个节点放到链表的前面就行了.大概方法

笔试题72. LeetCode OJ (59)

Spiral Matrix II 看上图就能知道这个提示要干什么的,给定一个 n 值,按照螺旋数组的存储特点将 1~N^2 存放到螺旋数组中. 思路:使用一个计数器(引用的方式使用),然后按照螺旋数组的方式去遍历的特点依次将该计数器的值赋给数组相应的位置,遍历完成后就是上述的样子了了,需要注意一下几点. 1.我们需要实现分配空间(讲vector的大小给定),否则肯定会崩溃的... 2.还是需要注意螺旋数组中一下常见问题,如重复问题,越界问题等等 代码如下: class Solution { pu