编程笔试题 - 无序整数数组中,第k小未出现的正偶数

一道编程笔试题,无序整数数组第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值的处理等问题
另这种做法会改变原来的数组,代码不保证完全正确,在自己的测试案例中是通过的,不保证案例覆盖得全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值