• leetcode 287 Find the Duplicate Number


    原题:

    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.

    题意:有n+1个数字,范围从1到n,其中有一个数字会重复多次,用低于O(n2)的时间复杂度算法找出重复的数字,空间复杂的为O(1)。

    解法:没有这些条件限制,就可以用二重循环直接找出来,或者用set/map等容器来做,正是由于这些条件限制,这题才变得有意思起来。

    很不幸我没有独立解决出这道题,看题解都看了半天才明白,所以一定要用烂笔头记下来。

    解法一:思路是采用了二分法+抽屉远离。首先解释一下为什么用二分法,因为O(n2)时间复杂度不能A,所以往下应该是n*logn,很容易联想到二分法,因为其复杂度为logn。

    抽屉原理是说假设你有11个苹果,要放进10个抽屉,那么至少有一个抽屉里是有两个苹果的。

    对应到这题,1~n的n+1个数字,有1个数字会至少重复两次。

    比如取数组为{1,2,2,3,4,5},一共6个数,范围是1~5,其中位数应该是(5+1)/2 = 3,那么,如果小于等于3的数的个数如果超过了3,那么重复的数字一定出现在[1,3]之间,否则出现在[4,5]之间。以该数组为例,中位数为3,小于等于3的数一共有4个,大于3的数有两个,所以重复的数字在[1,3]之间。

    代码:

    int findDuplicate(vector<int>& nums)
    {  
        int low = 1, high = nums.size()-1;    //low和high为数字的取值范围
    while(low<high) { int cnt = 0; //cnt为不大于中位数的数字个数 int mid = (low + high)/2; for(int i=0;i<nums.size();i++) { if(nums[i] <= mid) cnt++; } if(cnt>mid) { high = mid; //如果不大于mid的数字个数比mid多的话,则重复数字应该出现在[low, mid]之间 } else low = mid+1; //如果不大于mid的数字个数比mid少的话,说明重复的数字出现在后半段中[mid+1,high] } return low; }

    解法二:

  • 相关阅读:
    Vim Reference
    Java 8 Consumer、Supplier、Predicate、Function
    Java 8 Stream 用法
    Java 基础 Builder模式
    Spring/Spring-Boot 学习 使用自定义的ArgumentResolver
    架构之分布式图片存储系统架构
    微服务和SOA服务
    Centos 上 Tengine安装
    .NET平台上插拔姿势的AOP
    P1424 刷题记录
  • 原文地址:https://www.cnblogs.com/puyangsky/p/5271778.html
Copyright © 2020-2023  润新知