Find the Duplicate Number--重复数字问题

来源:互联网 发布:java 日期相差天数 编辑:程序博客网 时间:2024/05/17 22:47

问题描述

Given an array nums containing n+1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

Note:

  • You must not modify the array (assume the array is read only).
  • You must use only constant, O(1) extra space.
  • Your runtime complexity should be less than O(n2).
  • There is only one duplicate number in the array, but it could be repeated more than once.

该问题中文简单描如下:
n+1个整数组成的数组,每个整数范围在1到n之间(保证至少有一个数重复),假设只有一个重复数字,但可以重复多次
算法要求:
数组只读、空间复杂度常数阶、时间复杂度小于平方阶

思路:
假设数组长度为nlen,可以设定下界low=1,上界high=nlen,中间值mid=(low+high)/2,从理论上讲,如果数字没有重复,mid值和实际算出来数组的中值应该是一样的(最大值不大于数组长度,也就是没有条数字)。但由于问题中最大值不会大于数组长度,保证了 一定会有一个重复数字,利用mid可以把数组分成两部分,一部分的值小于等于mid,另一部分的值大于mid,计算出第一部分的个数count,如果第一部分的个数大于mid,可以知道重复的数字是在这一部分里,否则在另一部分里。该部分可以得到新的low值和high值,比如在第一部分,low不变,high=mid,这两个值是为了得到新的mid值服务的,(low和high只是数的序号,不是真正的数组值)然后可以更新low和high的值,以此类推。


下面举两个例子:
(1)数组{1,4,2,4,2}

循环条件:low<high
初始: low=1,high=5,mid=3,count=3

第一次:判断countmid
low=1,high=mid=3,mid=2,count=3

第二次: 判断countmid
low=1,high=mid=2,mid=1,count=1

第三次: 判断:count<mid
low=mid+1=2,high=2
循环结束

(2)数组{1,4,4,2,4}

循环条件:low<high
初始: low=1,high=5,mid=3,count=2

第一次:判断count<mid
low=mid+1=4,high=5,mid=4,count=3

第二次: 判断countmid
low=4,high=mid=4
循环结束


上述设计思路满足算法要求,时间复杂度o(nlog2n
注:
(1)low更新是为mid+1,否则会死循环(第一个例子)
(2)count的计算值是小于等于mid的数的个数,不是low和mid之间数值的个数。


c++程序如下:

class Solution {public:int findDuplicate(vector<int>& nums){    int n = nums.size();        int low = 1;        int high = n;        int mid;        while(low<high)        {             mid = (low + high) / 2;            if (count(low,high,nums)<=mid)                low=mid+1;            else                high= mid;        }        return low;    }    int count(int low, int high, vector<int>& nums)    {        int count0 = 0;        int n = nums.size();        int mid = (low + high) / 2;        for (int i = 0;i <n;i++)        {            if (nums[i] <=mid )                count0++;        }        return count0;    }};

关联问题:二分查找

0 0