面试题之数组中重复的数字

题目1
在一个长度为n的数组里的所有数字都在0~n-1范围内。数组中某些数字是重复的,但不知有几个数字重复,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
思路
若采用先排序,则其时间复杂度O(nlogn)
若采用哈希表,时间复杂度O(n),空间复杂度为O(n)。
最佳思路
从头扫描数组,扫描到下标为i的数字时,首先比较这个数字(m)是不是等于i,若是,接着扫描下一个,若不是,再拿它和第m个数字比较。若和第m个数字相等,就找到一个重复数字(改数字在下标i和m的位置都出现了);若和m个数字不等,就把他和第m个数字交换,把m放到属于他的位置。重复这个操作,直到发现重复数字。代码如下

bool duplicate(int numbers[], int length, int* duplication)

{if(numbers == nullptr || length <= 0)

    return false;

for(int i = 0; i < length; ++i)
{
    if(numbers[i] < 0 || numbers[i] > length - 1)
        return false;
}

for(int i = 0; i < length; ++i)
{
    while(numbers[i] != i)
    {
        if(numbers[i] == numbers[numbers[i]])
        {
            *duplication = numbers[i];
            return true;
        }

        // 交换numbers[i]和numbers[numbers[i]]             
        int temp = numbers[i];
        numbers[i] = numbers[temp];
        numbers[temp] = temp;
    }
}

return false;}

找到的重复数字通过参数duplication传给函数的调用者,函数的返回值表示数组中是否有重复数字。每个数字最多只要交换两次就能找到自己位置,所有操作都是在输入数组上进行,不需要额外分配内存。因此时间复杂度O(n),空间复杂度O(1)。

题目2:不修改数组找出重复数字
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字重复请找出数组中任意重复的数字,但不能修改输入数组。

最佳思路
把1~n的数字从中间数字m分为两部分,前边一半为1~m,后半为m+1~n,如果1~m的数字数目超过m,那么这一版区间一定包含重复的数字;否则,另一半m+1~n区间一定包含重复数字。继续把重复区间一分为2,直到找到重复数字,其原理和二分法类似,只是多出了统计区间数字数目。代码如下:

int getDuplication(const int* numbers, int length)

{if(numbers == nullptr || length <= 0)

    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)
    {
        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 end)
{
if(numbers == nullptr)
    return 0;

int count = 0;
for(int i = 0; i < length; i++)
    if(numbers[i] >= start && numbers[i] <= end)
        ++count;
return count;
}

如果输入长度为n的数组,则函数countRange将被调用O(nlogn)次,每次需要O(n)的时间,总的时间复杂度为O(nlogn),空间复杂度O(1)。

猜你喜欢

转载自blog.csdn.net/amychang230_/article/details/81675457