220.存在重復元素 III 【LeetCode】
給你一個整數數組 nums
和兩個整數 k
和 t
。請你判斷是否存在 兩個不同下標i
和j
,使得 abs(nums[i] - nums[j]) <= t
,同時又滿足 abs(i - j) <= k
。
如果存在則返回 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
提示:
0<=nums.length<=2?1040 <= nums.length <= 2 * 10^40<=nums.length<=2?104
?231<=nums[i]<=231?1-2^{31} <= nums[i] <= 2^{31} - 1?231<=nums[i]<=231?1
0<=k<=1040 <= k <= 10^40<=k<=104
0<=t<=231?10 <= t <= 2^{31} - 10<=t<=231?1
思路:由于對于一個數 xxx,只要找到存在[x?t,x+t][x-t,x+t][x?t,x+t]內的數就算成功,于是采用桶的思想,桶的大小設為 t+1t+1t+1,此時桶內的極差為 ttt,即桶內的任意的兩個數的差都符合條件,因此若某個桶同時出現兩個及以上的元素即說明 truetruetrue,而對于數 xxx 既可向前找 ttt 個數,也可向后找 ttt 個數,因此還需觀察相鄰桶中的元素,相鄰桶若存在與該數的差值不大于 ttt 則 truetruetrue,而由于某桶中出現兩個元素就直接成功了,因此相鄰桶要么沒有元素,要么只有一個元素(因此采用哈希表實現桶),因此只需比對常數級次數。而對于限制條件 kkk,只需模擬大小 k+1k+1k+1 的滑動窗口,從左到右遍歷數組,每次從右端加入新的數并且刪除最左端的數
官方題解:
class Solution {
public:int getID(int x, long w) {return x < 0 ? (x + 1ll) / w - 1 : x / w;}bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {unordered_map<int, int> mp;int n = nums.size();for (int i = 0; i < n; i++) {long x = nums[i];int id = getID(x, t + 1ll);if (mp.count(id)) {return true;}if (mp.count(id - 1) && abs(x - mp[id - 1]) <= t) {return true;}if (mp.count(id + 1) && abs(x - mp[id + 1]) <= t) {return true;}mp[id] = x;if (i >= k) {mp.erase(getID(nums[i - k], t + 1ll));}}return false;}
};作者:LeetCode-Solution
鏈接:https://leetcode-cn.com/problems/contains-duplicate-iii/solution/cun-zai-zhong-fu-yuan-su-iii-by-leetcode-bbkt/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
代碼解釋:
哈希映射函數
int getID(int x, long w) {return x < 0 ? (x + 1ll) / w - 1 : x / w;
}
正數部分很好理解,主要討論負數部分
- 首先將負數都加1,由圖可以看到加1后負數的坐標恰好與右邊正數形成鏡像映射,于是對稱的兩邊的 ididid 互為相反數
- 為解決 +0+0+0 與 ?0-0?0 的 ididid 沖突,于是將負數桶的 ididid 均減1