关于1-n中缺失的1个数字算法的优化

        这两天闲暇,回过头来看看一些基本的算法,发现还有很多可以优化的地方.记不清此题的出处了,好像是某大厂面试题,网上也有很多算法了,其中一些大神的算法看的心旷神怡,茅塞顿开,禁不住手痒也凑凑热闹:

        体的本意是在1-10000中缺失了一个数组,请写算法找出这个数字,当然了时间复杂度,空间复杂度越低越好.

        1.最简单的算法就是创建一个数组,数组的大小可以为10000个,然后在这9999个数里面找打那个就给那个数组做个记号,方法直接,容易理解,就是空间复杂度有点高.

        2.就是计算出1-10000的和,然后逐个减去这些数,最后的结果就是缺失的数字,空间复杂度,时间复杂度都不高,确实是个好办法.唯一的问题就是,如果不是10000,而是很大的一个数字呢?会不会溢出?当然这些可以进行控制,比如分段计算,但这样时间复杂度会高一些.

        3.然后就是大牛的算法,对1-10000逐个异或操作,然后结果在对给定的数逐个异或,最后的结果就是缺失的数字,这直接进行位运算,即使分成两次循环,时间复杂度也不过O(N*2),如果把这两个计算放到同一个循环中,那时间复杂度也就是O(N),空间复杂度O(1).真是完美.相关算法如下:

//count为N-1,是数组元素的个数
int Search(int* p, int count)
{
	int ret = 0;
	int i;
	for(i=0;i<count;i++)
	{
		ret ^= (i + 1);
		ret ^= *(p + i);
	}
	ret ^= count + 1;
	return ret ;
}

        4.然后我们在思考一下?0^1^2^3=0,4^5^6^7=0,8^9^10^11=0....然后发现每组4个数异或的结果都为0,既然这样我们为什么还要从1异或到10000在对数据进行异或求结果呢?看来我们可以省下很多步计算了.代码如下:

int NewSearch(int* p, int count)
{
	int ret = 0;
	int t = (count + 1) % 4;
	int i;
	for (i = count + 1; i > count - t; i--)
	{
		ret ^= i;
	}
	for (i = 0; i < count; i++)
	{
		ret ^= *(p + i);
	}
	return ret;
}

这样,总体的计算就少了很多,尤其是当N很大的时候,更加明显.

全部代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#define WIN32
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#ifdef WIN32
#include<windows.h>
#else
#include<sys/time.h>
#endif
#ifdef WIN32
int gettimeofday(struct timeval* tp, void* tzp)
{
	time_t clock;
	struct tm tm;
	SYSTEMTIME wtm;
	GetLocalTime(&wtm);
	tm.tm_year = wtm.wYear - 1900;
	tm.tm_mon = wtm.wMonth - 1;
	tm.tm_mday = wtm.wDay;
	tm.tm_hour = wtm.wHour;
	tm.tm_min = wtm.wMinute;
	tm.tm_sec = wtm.wSecond;
	tm.tm_isdst = -1;
	clock = mktime(&tm);
	tp->tv_sec = (long)clock;
	tp->tv_usec = wtm.wMilliseconds * 1000;
	return(0);
}
#endif

struct timezone
{
	int tz_mainuteswest;
	int tz_dsttime; 
};

void createArr(int* p,int count)
{
	int r = 1+rand()%(count+1);
	int j;
	for (j = 1; j <= count; j++)
	{
		if (j < r) {
			*(p++) = j ;
		}
		else
		{
			*(p++) = j + 1;
		}
	}
}

void shuffle(int* p , int count)
{
	int i = count;
	int j ,tmp;
	while (i)
	{
		j = rand() % (i--);
		tmp =*(p+j);
		*(p+j) = *(p+i);
		*(p+i) = tmp;
	}
}


//优化后的算法
int NewSearch(int* p, int count)
{
	int ret = 0;
	int t = (count + 1) % 4;
	int i;
	for (i = count + 1; i > count - t; i--)
	{
		ret ^= i;
	}
	for (i = 0; i < count; i++)
	{
		ret ^= *(p + i);
	}
	return ret;
}

//很牛的算法
int Search(int* p, int count)
{
	int ret = 0;
	int i;
	for(i=0;i<count;i++)
	{
		ret ^= (i + 1);
		ret ^= *(p + i);
	}
	ret ^= count + 1;
	return ret ;
}

int main() 
{
	//设置随机数种子
	srand((int)time(0));
	int count = 999999999;
	int *arr =(int*)malloc(count*sizeof(int));
	//生成顺序的数组
	createArr(arr, count);
	//乱序一下
	shuffle(arr, count);
	struct timeval tv1, tv2;
	struct timezone tz;
	//开始计时
	gettimeofday(&tv1, &tz);
	int ret= Search(arr, count);
	gettimeofday(&tv2, &tz);
	printf("缺失的数字是:%d\n", ret);
	//计算用时
	int ms=(int)((tv2.tv_usec - tv1.tv_usec)/1000);
	ms = tv2.tv_usec > tv1.tv_usec ? ms : ms + 1000;
	int s = tv2.tv_usec > tv1.tv_usec ? (int)(tv2.tv_sec - tv1.tv_sec) : (int)(tv2.tv_sec - tv1.tv_sec - 1);
	printf("用时%d秒,%d毫秒\n", s, ms);

	//开始计时
	gettimeofday(&tv1, &tz);
	ret = NewSearch(arr, count);
	gettimeofday(&tv2, &tz);
	printf("缺失的数字是:%d\n", ret);
	//计算用时
	ms = (int)((tv2.tv_usec - tv1.tv_usec) / 1000);
	ms = tv2.tv_usec > tv1.tv_usec ? ms : ms + 1000;
	s = tv2.tv_usec > tv1.tv_usec ? (int)(tv2.tv_sec - tv1.tv_sec) : (int)(tv2.tv_sec - tv1.tv_sec - 1);
	printf("用时%d秒,%d毫秒\n", s, ms);
	
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值