编程笔试题

来源:互联网 发布:vs.php for vs2015 编辑:程序博客网 时间:2024/05/16 10:29

一道编程笔试题,无序整数数组第n小未出现的正偶数

有一个无序整数数组,要求找到第n小未出现的正偶数,实现函数
unsigned int getMinEven(int *a,int len,int k)
示例:
{-3,-2,2,4},4,1 输出:6
{2,4,7,8,5,10},6,2 输出:12
{2,2,2,2,2,2},6,2 输出6
要求时间复杂度为O(N),空间复杂度为O(1)

这道题来自CVTE的笔试是,改自IBM的笔试题 ,原题是要找出最小的未出现的正整数,不过思路大致相同
看到题后,会有先排序再查找的惯性思路,用O(nlgn)的快速排序、归并排序或者堆排序都不符合要求
排完之后,再对数组进行判断,复杂度也为O(nlgn) ,最后复杂度为O(nlgn) ,没能达到O(N)

最初的思路
于是再经过一番思考后,觉得可以假设整个数组已经排好,当出现一个不符合条件的数后,就对假定的正偶数进行调整,一直到整个数组扫描完,这样下来复杂度是O(N),于是开始写代码

int n_little(int *a, int length, int n){    if (a == NULL || length <= 0||n<0) return 0;    int target = n * 2; //如果整个数组是排好的正偶数,目标值就是n*2    int const_temp = target;    if (n > length) return target;    for (int i = 0; i < length; i++)    {        if (a[i]%2 == 0 &&a[i]>0&& a[i]<= const_temp) {            target += 2;        }    }    return target;}

对案例进行想象输入后,发现最后一个数组是不通过的,相同的正偶数无法知道之前是否已经扫描过,这样子才发现这个思路还是有缺陷,想要进行修补,如扫描一次后再扫描看有没有重复的在支规定范围内的数,但这样子的查找可能会增加空间的使用,无法符合复杂度的要求

解决相同正偶数的问题

于是对上面的想法进行修正,假如在扫描的过程,能不耗费空间的情况下把相同的符合条件的正偶数进行统计。这样子一来,想要不耗费多余的空间的话,就只能在原数组上进行替换
当然,要替换的数肯定是用不到的,不符合要求的数。
于是,把思路理清之后就可以写代码了

int getMinEven(int arr[],int length,int k){    if (k == 0 || arr==NULL||length<=0)        return 0;    int left = 0; //left表示当前符合条件正偶数的位置    int r = length; //如果一个数字过大(不合法),就会被扔掉,r表示这个右边界    while (left < r)    {        if (arr[left] == (left + 1)*2)        {            left++;        }        else if (arr[left]> r*2 || arr[left] <=(left +1)*2 || arr[arr[left]/2-1 ] == arr[left])//不合法        {            arr[left] = arr[--r]; // --r注意,一旦不合法,这个右边界是会缩小的        }        else//合法但是没有在理想的位置上        {            //cout << "合法" << "\n";            int temp = arr[left];            arr[left] = arr[arr[left]/2 - 1];            arr[temp/2 - 1] = temp;        }    }    int target = 0;    for (int i = 0;i < length; i++ )    {        if (arr[i] != (i + 1) * 2)        {            --k;        }        if (k == 0)        {            target = (i + 1) * 2;            break;        }    }    if(k != 0)    {        target = length * 2 + k*2; //超出的部分    }    return target;}int main(){    int a[6]= {2,2,2,2,2,2};    //int a[6] = { -2,2,2,4,6,9 };    int k = getMinEven(a, 6, 7);    cout << k;    system("Pause");}

当然了,在这过程中,要注意到边界的问题
同时当得到一个符合条件正偶数数组后,k值的处理等问题
另这种做法会改变原来的数组,代码不保证完全正确,在自己的测试案例中是通过的,不保证案例覆盖得全

原创粉丝点击