面试题3(二):不修改数组找出重复的数字

// 面试题3(二):不修改数组找出重复的数字
// 题目:在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至
// 少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的
// 数组。例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的
// 输出是重复的数字2或者3。

解题思路:

不能修改数组,可以创建一个长度为n+1的辅助数组,空间复杂度为O(n)。

如果用时间换空间的话,可以使用二分查找的思想。

元素范围为1~n,但是有n+1个元素,说明有某个数字重复了。

以中间数字m为界限,分成两部分,1~m和m+1~n。

如果1~m的元素个数超过了m,说明重复元素在前半部分,再次划分1~m。

重复此过程,直到最后找出重复元素。

伪代码:

if(输入参数无效)
    return -1;
int start=1; int end=length-1; while(start<=end){ int middle=区间中点; int count=start到middle之间元素个数; if(区间上下限相等){ if(count大于1) return start; else return -1; } if(count>(middle-start+1)) end=middle; else start=middle+1; } return -1;

c/c++代码:

int getDuplication(const int* numbers,int length){
    //校验输入参数的有效性
    if(numbers==nullptr||length<0){
        return -1;
    }
    for(int i=0;i<length;i++){
        if(numbers[i]<1||numbers[i]>length-1){
            return -1;
        }
    }

    //二分查找重复元素
    int start=1;
    int end=length-1;
    while(end>=start){
        int middle=((end-start)>>1)+start;
        int count=countRange(numbers,length,start,middle);
        //区间上下限相等
        if(end==start){
            //元素数量大于1,成功查找
            if(count>1)
                return start;
            else
                break;
        }

        //区间上下限不等,继续二分查找
        if(count>(middle-start+1))
            end=middle;
        else   
            start=middle+1;
    }
    return -1;
}
//获取区间元素个数
int countRange(const int* numbers,int length,int start,int middle){
    if(numbers==nullptr||length<0){
        return -1;
    }
    
    int count=0;
    for(int i=0;i<length;i++){
        if(numbers[i]>=start&&numbers[i]<=middle)
            count++;
    }
    return count;
}

参考资料:

剑指offer面试题3(二)

猜你喜欢

转载自www.cnblogs.com/BoqianLiu/p/9404517.html