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