【时间复杂度、空间复杂度练习】- 消失的数字

题目描述

描述
数组nums包含从0到n的所有整数,但其中缺了一个。编写代码找出那个缺失的整数。你有办法在O(N)时间内完成吗?
示例

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

解题分析:

思路1:先排序,再判断前一个是不是比后一个多/少1。
如果是升序排序,后一个元素不满足比前一个元素多1,则消失的数字为下标为i的元素+1,如果是升序缺第一个先判断第一个是不是0,缺最后一个判断i == 数组元素个数-1。
如果是降序排序,后一个元素不满足比前一个元素少1,则消失的数字为下标为i的元素-1,如果是降序缺第一个先判断第一个是不是n,缺最后一个判断i == 数组元素个数-1。
时间复杂度:先算排序的准确执行次数,再计算比较的次数。F(N) = n^2 + n -1,n为元素个数。
故时间复杂度为O(n^2),不符合要求。即使是快速排序的时间复杂度O(N*log2 N),也达不到O(1)。
空间复杂度:F(N) = 7,故空间复杂度为O(1)。

思路2:对不缺的数组求和,再减去缺失的数组的和。
(0+1+2+…+n)-(a[0]+a[1]+a[2]+…a[n-1])
把0到N的数加到一起结果是ret1,再把数组中的数加到一起结果是ret2
ret1 - ret2就是要找的数。
时间复杂度:先计算求缺失的数组的和的次数,再计算求不缺失数组的和的次数。F(N)=n + (n+1),n为元素个数,故时间复杂度为O(N)。
空间复杂度:F(N) = 6,故空间复杂度为O(1)。

思路3:假设num是要找的数,必须初始化为0。先跟数组中的数异或,后与0到n之间所有的数异或,结果num就是要找的数。
举例:
假设完整数组元素是01234 ,实际数组少3,即nums[4]={0,1,2,4},numsSize = 4。
上面循环异或完后是 x = 0 ^ 1 ^ 2 ^ 4,
下面循环异或结束后,就变成了 x = x ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ,最终为x = 3。
原理:相同的两个数异或是0,0 ^ a = a。
先计算求缺失的数组异或的次数,再计算求不缺失数组异或的次数。F(N)=n + (n+1),n为元素个数,故时间复杂度为O(N)。
空间复杂度:F(N) = 5,故空间复杂度为O(1)

思路4:开辟一个N的空间。数组中的值是几就在第几个位置写下这个值。
时间复杂度:O(N)。F(N)=n + (n+1),n为元素个数。
空间复杂度:F(N) = n+1 + 5,故空间复杂度:O(N)。


代码实现:

方法1

#include <stdio.h>
void Sort(int nums[],int numsSize)
{
	for(int i = 0;i<numsSize-1;i++)
	{
		for(int j = 0;j<numsSize-i-1;j++)
		{
			if(nums[j] > nums[j+1])
			{
				int tmp = nums[j];
				nums[j] = nums[j+1];
				nums[j+1] = tmp;
			}
		}
	}
}
int missingNumber(int* nums, int numsSize)
{
	Sort(nums, numsSize);//升序
	//0-9
	//123456789
	//升序先判断第一个元素是不是0
	if (nums[0] != 0)
		return 0;
	int i = 0;
	//numsSize个元素,一共numsSize-1次比较,即(numsSize-2) -0 +1
	for (i = 0; i < numsSize - 1; i++)//nums数组最后一个元素的下标i+1 == numsSize - 1
	{
		if (nums[i + 1] - nums[i] != 1) //i <= numsSize - 2
		{
			return i + 1;
		}
	}
	//0-9
	//012345678
	if (i == numsSize - 1)
	{
		return i + 1;
	}
}
int main()
{
	int nums[] = { 9,6,4,2,3,5,7,0,1 };
	int numsSize = sizeof(nums) / sizeof(nums[0]);
	int missNumber = missingNumber(nums, numsSize);

	printf("缺失的数字为:%d\n", missNumber);
	return 0;
}

方法2

int missingNumber(int* nums, int numsSize)
{
	int x = 0;
	int y = 0;
	//缺失的数组求和
	for (size_t i = 0; i < numsSize; i++)
	{
		x += nums[i];
	}
	//再0-n中的数求和
	for (size_t i = 0; i <= numsSize; i++)//注意:这里控制条件为i <= numsSize或i < numsSize+1
	{
		y += i;
	}
	return y - x;
}

方法3

int missingNumber(int* nums, int numsSize)//nums为数组,numsSize为数组的元素个数
{
	int x = 0;//用来保存异或值的结果,0和任何数异或仍为任何数
	//先和数组中的数异或
	for (size_t i = 0; i < numsSize; i++)
	{
		x ^= nums[i];
	}
	//再和【0,n】中的数异或
	for (size_t i = 0; i <= numsSize; i++)//注意:这里控制条件为i <= numsSize或i < numsSize+1
	{
		x ^= i;
	}
	return x;
}

方法4

int missingNumber(int* nums, int numsSize)//nums为数组,numsSize为数组的元素个数
{
	int* arr = malloc(sizeof(int) * (numsSize + 1));
	for (int i = 0; i < numsSize; i++)
	{
		arr[nums[i]] = nums[i];
	}

	for (int i = 0; i < (numsSize + 1); i++)
	{
		if (arr[i] != i)
			return i;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值