《剑指offer》第一篇---消失的数字

Posted 花嵩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《剑指offer》第一篇---消失的数字相关的知识,希望对你有一定的参考价值。

前言:

  • 博主实力有限,博文有什么错误,望各位大佬,不吝赐教,非常感谢!

  • 这是博主的新专栏《剑指offer》第一篇,希望各位大佬多多支持,感谢!

  • 如果对按位与&,按位异或^ ,按位或|,&&且,||或,不是太明白的见我另外一篇博客

题目

消失的数字

一个数组中含有从0到20的所有数字,但是数组中缺少了0到20中的一个数,请你找出这个消失的数字

高效方法一:双目操作符按位异或^

补充

  • 按位异或^ 的规则是:

exp:a^b

比较a与b中二进制补码(!!!)中每位,相同那么新形成的二进制对应位为0,不相同的为1

exp:

a= 1;b= 3;

a的补码:

00000000 00000000 00000000 00000001

b的补码:

00000000 00000000 00000000 00000011

a^b后的新的二进制补码是:

00000000 00000000 00000000 00000010

  • **按位异或的一些规律:**(!!!)
  • 0与任何数异或都是任何数

  • **1^ 2 ^ 3 ^2 ^ 3 =1**

这是理解本题目的**关键点**

!!!

思路:

正是因为1 ^ 2 ^ 3 ^4 ^5 ^ 2 ^3 ^ 4^ 5=1

因此对于本题;将数组中所有数全部 按位异或 ^到一起
x=arr[0]^ arr[1]^ arr[2]^ … arr[19]

之后再将0到20的数字异或到一起

那么最后,x必然是那个消失的数

毕竟0到20重复的数都^没了

代码

int main()
{
	int x = 0;//用于存放按位异或的数据
	int arr[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20 };
	int sz = sizeof(arr) / sizeof(*arr);
	for (int i = 0; i < sz; i++)
	{
		x ^= arr[i];
	}
	//x=0^1^2^3....^20;
	for ( int i = 0; i < 21; i++)
	{
	
		x ^= i;
	}
	//这次for循环后,连续的^中,相同的数据都被抵消,只剩下一个消失的那个数
	printf("%d\\n", x);

}

时间复杂度:0(N),空间复杂度:0(1)

优点:算法效率高

缺点:

只能用于查找消失的一个数,对于消失的数字过多情况不能处理,即使分组也不好。-----分组的思想在我另外一篇博客:单身狗

一般方法:折半查找法,与对比排序法

二分查找法:

  • 思路

依次拿0到20中的数字 在数组中用二分查找的方法查找

  • 代码:
   //折半查找
	for (int i = 0; i <= 20; i++)//i为要查找的数
	{
		int left = 0;//存放数组左边下标
		int right = sz - 1;//存放数组右边下标
		int mid = 0;//数组中间数据的下标,之所以定义在外面是因为,每次for循环,、
		           //mid生命周期结束,这样就可以重置mid
		while (left <= right)
		{

			mid = (left + right) / 2;
			if (arr[mid] > i)//说明要找的数据在mid的左边,排序后,左边的数据都小于arr[mid]
			{
				right = mid - 1;
			}
			else if (arr[mid] < i)//说明要找的数据在mid的右边,排序后,右边的数据都小于arr[mid]
			{

				left = mid + 1;

			}
			else
			{

				break;//break,只能结束一层循环即while,
			}
		}
		
		if (left > right)//如果i没有在数组中找到就输出I
		{
			printf("%d\\n", i);
		
		}
	}
	
	
}

  • 时间复杂度:0(N2)空间复杂度:0(1)

  • 优点可以处理消失数字多的情况。

  • 缺点必须要对数组排序。

对比排序法:

  • 思想:将数组排序后,将0到20的数组依次与数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6L4g3Ptr-1631111664941)(前言:.assets/image-20210908164408529-16310906497221.png)]

代码:

int main()
{

	int arr[] = { 16,17,18,19,0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,20 };
	int sz = sizeof(arr) / sizeof(*arr);//计算数组长度
	//选择法排序
	for (int i = 0; i < sz - 1; i++)//选择法排序数组的思想就是,
		                           //拿第i个元素,将其与之后的数据进行比较,
		                           //拿到最小数据的下标。
	{
		int min = i;//用于存放下标
		for (int j = i + 1; j < sz; j++)
		{
			if (arr[j] < arr[min])
			{
				min = j;
			}
		}//通过此层循环,min会得到数据最小的数组下标

		if (min != i)//如果min得到下标不是i就交换下标i与下标min的值
		{
			int tmp = arr[i];
			arr[i] = arr[min];
			arr[min] = tmp;
		}

	}

	int flag = 0;//记录数组下标

	for (int i = 0; i < 21; i++)
	{

		if (i ^ arr[flag])//^后如果不相等,那么异或后就是非0,也就是i为缺少的数字
		{
			printf("%d\\n",i);

		}
		else
		{

			flag++;
		}

	}


}
  • 时间复杂度:0(N2),空间复杂度:0(1)

  • 优点可以实现 消失的数字多的情况

  • 缺点:也是必须对数组排序。

总结:

  • 博主目前没想到,不用按位异或的方法,不对数组排序的情况下,找到消失的数字的方法。
  • 若有那为大佬,知道这种不排序就可以找到的消失的数字方法,希望大佬能留言,非常感谢!

以上是关于《剑指offer》第一篇---消失的数字的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer梯度消失和梯度爆炸

LeetCode810. 黑板异或游戏/455. 分发饼干/剑指Offer 53 - I. 在排序数组中查找数字 I/53 - II. 0~n-1中缺失的数字/54. 二叉搜索树的第k大节点(代码片段

剑指offer--缺失的数字

剑指offer第一层

剑指offer第一层

剑指offer第一层