• 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; }

    解法二:

  • 相关阅读:
    How To Move a MySQL Data Directory to a New Location on Ubuntu 16.04
    Mysql Docker Container Command
    svg_png
    png格式图片转为svg格式图片
    Ubuntu Server如何配置SFTP(建立用户监狱)
    ubuntu用户添加adduser, useradd并给予sudo权限
    Setup FTP server on Ubuntu 14.04
    Ubuntu Server 16.04.1系统安装
    1.Linux下生成密钥
    Linux查看设备命令
  • 原文地址:https://www.cnblogs.com/puyangsky/p/5271778.html
Copyright © 2020-2023  润新知