题目:
一排N(最大1M)个正整数+1递增,乱序排列,第一个不是最小的,把它换成-1,最小数为a且未知求第一个被-1替换掉的数原来的值,并分析算法复杂度。
思想:
(1)很容易想到排序,但如果是比较排序的想法,时间复杂度会达到O(NlogN);此题我们仍然可以利用数与下标之间的关系来确定(和前一个找重复值面试题思想差不多),首先明确一点所有的数均小于一个整数;首先遍历一遍数组,得到该数组的最小值min(-1除外),最大值max;再次遍历一遍数组,所有数组值均减去min,得到新的数组,n = 2 *max+2。
(2)新数组那我们开始从index=1到index=length-1遍历数组,过程如下:
(2.1)若A[index]< n,则temp=A[index],否则temp=A[index]-n。
(2.2)若A[temp]<n,表示数值A[temp]未被访问过,更新A[temp]=A[temp]+n
(3)最后从index=1重新遍历数组,若A[index]< n,则该下标表示未访问过,那么直接返回A[index]+min即为替换的值。
(4)上述思想归根到底是采用了一种hash冲突的思想,根据所有的数均小于n,来进行处理的;由于只遍历几遍数组,故时间复杂度为O(n),只用到常数个变量,故空间复杂度为O(1)。
程序实现:
#include<stdlib.h>
int find_number(int *A, int length, int n)
{
int temp;
int index;
for(index = 1; index < length; index++){
if(A[index] < n){
temp = A[index];
}else{
temp = A[index] - n;
}
if(A[temp] < n){
A[temp] += n;
}
}
for(index = 1; index < length; index++){
if(A[index] < n){
return index;
}
}
return -1;
}
int main(void)
{
int A[] = {-1,6,8,11,5,10,12,14,13,9,15};
int i;
int max = A[1];
int min = A[1];
printf("A[]:%d ", A[0]);
for(i = 1; i < sizeof(A) /sizeof(A[0]) ; i++){
printf("%d ", A[i]);
if(min > A[i])
min = A[i];
if(max < A[i])
max = A[i];
}
printf("\n");
A[0] = 1;
for(i = 1; i < sizeof(A) /sizeof(A[0]) ; i++){
A[i] -= min;
}
int a = find_number(A, sizeof(A) /sizeof(A[0]), 2 * max + 2);
printf("search numbers:%d\n", a + min);
return 0;
}