LeetCode ---- 缺失数字

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:

输入: [3,0,1]
输出: 2


示例 2:

输入: [9,6,4,2,3,5,7,0,1]
输出: 8

题目说明:你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?

这道题我的思路其实并不丰富,最初想的就是自己建一个比传到函数中的vector长度大1的vector,然后把序列中的数按数字存到相应的下标。最后判断是哪个没有存进去,返回就OK。但是提交之后,发现效率不是很高,耗时28ms。接着想用关联容器来实现,但是也没有找到合适的方法。然后去看题解去了,发现了一位大神写了四种方法,真的是让我顶礼膜拜。推荐你们看一下:https://leetcode-cn.com/problems/missing-number/solution/que-shi-shu-zi-by-gpe3dbjds1/

特别是他写的异或和等差数列的方法,真的是很牛逼。位运算本身就很快,所以异或这个方法真的绝了,确实不是一般人能想到的。

先来看一下我的方法:

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        if (nums.empty())
			return 0;
		int size = nums.size();
		vector<int> result(size+1,-1);
	
		for (int val : nums)
		{
			result[val] = 1;			
		}

		for (int i = 0; i < result.size(); ++i)
		{
			if (result[i] != 1)
			{
				return i;
			}
		}
		return 0;
    }
};

这个方法确实不好,虽然时间上是28ms,但是却额外浪费了空间。

所以可以看看以下方法:

1、排序

题目中说的很清楚,算上缺少的数,所有的数与下标都是一一对应的。那么n个数中缺少一个,那么剩下的数排序之后肯定有与下标不对应的,那么找到第一个不对应于的就知道是缺少了哪个数。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        if (nums.empty())
			return 0;
		sort(nums.begin(), nums.end());
		for (int i = 0; i < nums.size(); ++i)
		{
			if (nums[i] != i)
				return i;
		}
		return nums.size();
    }

};

这种方法执行下来是44ms。泛型算法本身的排序也很耗时间,再来一次循环遍历,时间效率上来说确实不太好。

2、异或

异或的特性也是解决这道题的一个好办法。因为加上缺少的数字,vector中的每个数和相应的下标都是相等的。那么缺少了一个数字,可是它本应对应的下标却是唯一存在的。所以循环异或就可以判断出缺少哪个数字。

class Solution {
public:
	int missingNumber(vector<int>& nums) {
		if (nums.empty())
			return 0;
		int x = nums.size();
		for (int i = 0; i < nums.size(); ++i)
		{
			x ^= nums[i];
			x ^= i;
				
		}
		return x;
    }
};

异或方法执行下来是24ms

3、等差数列法

可以发现这个vector中的数据都是有序的,并且差值为1。那么利用我们高中学习过的等差数列先求得它的和,再减去vector里面的值,就可以得到缺少的数字。

等差数列求和公式:Sn = na1 + (n(n-1)/2)*d;由题可知,a1=0,d=1;

那么针对这道题的求和公式就可以演变为:Sn = n(n-1)/2;n为项数

又根据题的意思可以得知,vector中的最大数肯定是和数组大小一致的,但是却缺少一个,所以这里的n都要加上1,才能得到本应的和。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
       if (nums.empty())
			return 0;
		int sum = (nums.size()*(nums.size() + 1)) / 2;
		for (int i = 0; i < nums.size(); ++i)
		{
			sum -= nums[i];
		}
		return sum;
    }

};

等差数列法求出来是最快的,只需16ms。

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值