zoukankan      html  css  js  c++  java
  • [LeetCode]103. 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.

    解法:使用鸽巢原理可以很简单的证明。注意Note的第四点,有且仅有一个重复的数字,但是这个重复的数字可能出现两次以上。这说明这n+1个数并不是一定包含了[1,n]中的每个数。开始时没注意到这点,用

    return accumulate(nums.begin(), nums.end(), 0) - ((nums.size() - 1) * nums.size() >> 1);

    结果显然错误。因为不能修改输入数组且空间复杂度要求为O(1),所以不能用排序,也不能使用HashTable。因为时间复杂度必须低于O(n^2),因此不能使用暴力破解法。

    //修改输入数组的排序方法
    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size(), i = 0;
            sort(nums.begin(), nums.end());
            for(; i < n - 1; ++i) {
                if(nums[i] == nums[i + 1]) break;
            }
            return nums[i];
        }
    };
    //额外O(n)空间的Hash方法
    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size(), i = 0;
            vector<int> cnt(n, 0);
            for (; i < n; ++i) {
                if (++cnt[nums[i]] > 1) break;
            }
            return nums[i];
        }
    };
    //O(n^2)时间的暴力破解法
    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size(), i = 0, j = 0;
            for (i = 0; i < n - 1; ++i) {
                for (j = i + 1; j < n; ++j) {
                    if (nums[i] == nums[j]) break;
                }
                if (j != n && nums[i] == nums[j]) break;
            }
            return nums[i];
        }
    };

    考虑到这n+1个数是在有序的[1,n]中选取的,因此可以考虑在[1,n]中使用二分查找,即在[1,n]中每次折半选出一个数mid,遍历输入数组统计小于等于mid的元素个数cnt。如果cnt>mid,说明重复值在[1,mid-1]之间,否则在[mid+1,n]之间。时间复杂度O(nlogn),空间复杂度O(1)。

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size(), left = 1, right = n - 1;
            while (left <= right) {
                int mid = (left + right) >> 1, cnt = 0;
                for (int i = 0; i < n; ++i) {
                    if (mid >= nums[i]) ++cnt;
                }
                if (cnt > mid) right = mid - 1;
                else left = mid + 1;
            }
            return left;
        }
    };
  • 相关阅读:
    今日总结
    每日总结
    每日总结
    每日总结
    重返现世
    [PKUWC2018]随机游走
    [HAOI2015]按位或
    [NOI2020] 超现实树
    [NOI2017] 游戏
    [CSACADEMY]Card Groups
  • 原文地址:https://www.cnblogs.com/aprilcheny/p/5032243.html
Copyright © 2011-2022 走看看