《算法分析与设计》Week 19

287. Find the Duplicate Number


Description:

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:

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


Solution:

一、题意理解

      给定一个长度为n+1的数组,每一个数都是在1~n之间,那么至少会有一个数是重复的。现在假设只有一个重复的数,则找出这个数。

      注意:

      1、不能修改原数组(数组是只读的)

      2、空间复杂度为O(1)

      3、时间复杂度需要小于O(n^2)

      4、只有一个重复的数字,但它可能重复的不止一次。


二、分析

     1、一不能修改原数组,二空间复杂度为O(1),所以无法通过计数的方式来查找这个数,只能通过遍历查找的方式。说起查找,普通方法就是针对数组中的每一个数,都再遍历一次数组看是否有重复的数,就算优化后,从当前数的下一个数开始搜索,时间复杂度依然为O(n^2)。

      2、查找算法中,除了所谓Hash映射之外,二分查找是效率最高的,那么我们是否可以利用二分查找呢。根据数组的特点,对于一个数字 i ,设数组中 <= i 的数的数量为count,那么如果count <= i,那么肯定有一个比 i 大的数重复,使得一个比i小的数被“冲”掉了,那么这个数肯定大于i。否则,这个数肯定<=i。根据这个特点,我们可以以1~n为范围做二分查找,令i = (1 + n) / 2,每一次都计算count (where num<=i)来缩小一半的查找范围,知道最后能查找到这个重复的数。

      3、空间复杂度为O(1),时间复杂度为O(nlog(n)),代码如下:

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int begin = 1;
        int end = nums.size() - 1;
        int count, mid;
        vector<int>::iterator it;

        while(begin < end)
        {
            mid = (begin+end) / 2;
            count = 0;
            for(it = nums.begin(); it != nums.end(); ++it)
            {
                if(*it <= mid)
                    count++;
            }
            if(count <= mid)
                begin = mid+1;
            else
                end = mid; 
        }
        return end;
    }
};


        4、还有更高级的做法,将数组看做一个链表,以下标为索引,问题能够转换为链表求环的问题。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值