LeetCode #220 Contains Duplicate III 存在重复元素 III

220 Contains Duplicate III 存在重复元素 III

Description:
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

Example:

Example 1:

Input: nums = [1,2,3,1], k = 3, t = 0
Output: true

Example 2:

Input: nums = [1,0,1,1], k = 1, t = 2
Output: true

Example 3:

Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false

题目描述:
在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。

如果存在则返回 true,不存在返回 false。

示例 :

示例 1:

输入: nums = [1,2,3,1], k = 3, t = 0
输出: true

示例 2:

输入: nums = [1,0,1,1], k = 1, t = 2
输出: true

示例 3:

输入: nums = [1,5,9,1,5,9], k = 2, t = 3
输出: false

思路:

桶排序
将数字分成 t + 1个区间, 相同的区间内两个元素差必定小于等于 t
相邻区间才需要判断绝对值是否在区间内
比如如果一个人出生在 2月, 需要找 30天之内出生的人, 2月出生的一定可以, 1月和 3月出生的人也有可能, 这里是把月份当作桶
由于下标差需要小于等于 k, 所以需要将距离大于 k的元素删除(滑动窗口)
时间复杂度O(n), 空间复杂度O(k), 只需要对每个元素遍历一次, 哈希表查询时间 O(1), 每个桶最多一个数字, 同时最多存在 k个桶

代码:
C++:

class Solution 
{
public:
    bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) 
    {
        if (t < 0 or k < 0) return false;
        long bucket_size = (long)t + 1;
        unordered_map m;
        for (int i = 0; i < nums.size(); i++)
        {
            int bucket = nums[i] < 0 ? nums[i] / bucket_size - 1 : nums[i] / bucket_size;
            if (m.find(bucket) != m.end()) return true;
            if ((m.find(bucket + 1) != m.end() and labs(m[bucket + 1] - nums[i]) <= t) or (m.find(bucket - 1) != m.end() and labs(m[bucket - 1] - nums[i]) <= t)) return true;
            m[bucket] = nums[i];
            if (i >= k) m.erase(nums[i - k] / bucket_size);
        }
        return false;
    }
};

Java:

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        if (t < 0 | k < 0) return false;
        Map hash = new HashMap<>();
        long bucketSize = (long)t + 1;
        for (int i = 0; i < nums.length; i++) {
            long m = getBacket(nums[i], bucketSize);
            if (hash.containsKey(m)) return true;
            if ((hash.containsKey(m - 1) && Math.abs(nums[i] - hash.get(m - 1)) < bucketSize) | (hash.containsKey(m + 1) && Math.abs(nums[i] - hash.get(m + 1)) < bucketSize)) return true;
            hash.put(m, (long)nums[i]);
            if (i >= k) hash.remove(getBacket(nums[i - k], bucketSize));
        }
        return false;
    }

    private long getBacket(long i, long bucketSize) {
        return i < 0 ? (i + 1) / bucketSize - 1 : i / bucketSize;
    }
}

Python:

class Solution:
    def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        if t < 0 or k < 0:
            return False
        buckets, buckets_size = {}, t + 1
        for i in range(len(nums)):
            bucket_num = nums[i] // buckets_size
            if bucket_num in buckets:
                return True
            buckets[bucket_num] = nums[i]
            if (bucket_num - 1) in buckets and abs(buckets[bucket_num - 1] - nums[i]) <= t or (bucket_num + 1) in buckets and abs(buckets[bucket_num + 1] - nums[i]) <= t:
                return True
            buckets[bucket_num] = nums[i]
            if i >= k:
                buckets.pop(nums[i - k] // buckets_size)
        return False

你可能感兴趣的:(LeetCode #220 Contains Duplicate III 存在重复元素 III)