@@ -35,7 +35,55 @@ https://leetcode-cn.com/problems/contains-duplicate-iii/
35
35
36
36
- 暂无
37
37
38
- ## 思路
38
+ ## 暴力(超时)
39
+
40
+ ### 思路
41
+
42
+ 最简单的思路就是双层循环,找出所有的两两组合。然后逐个判断其是否满足 ` nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。 `
43
+
44
+ ### 代码
45
+
46
+ ``` python
47
+ class Solution :
48
+ def containsNearbyAlmostDuplicate (self , nums : List[int ], k : int , t : int ) -> bool :
49
+ for i in range (len (nums)):
50
+ for j in range (i + 1 , len (nums)):
51
+ if abs (nums[i] - nums[j]) <= t and j - i <= k:
52
+ return True
53
+ return False
54
+ ```
55
+
56
+ ** 复杂度分析**
57
+
58
+ - 时间复杂度:$O(N ^ 2)$
59
+ - 空间复杂度:$O(1)$
60
+
61
+ ## 暴力 + 剪枝 (超时)
62
+
63
+ ### 思路
64
+
65
+ 上述的内存循环可以稍微优化一下, 之前我们从 i + 1 到 len(nums),实际上我们只需要 i + 1 到 min(len(nums), i + k + 1)。这样我们的 ` j - i <= k ` 也可以省略了。
66
+
67
+ ### 代码
68
+
69
+ ``` python
70
+ class Solution :
71
+ def containsNearbyAlmostDuplicate (self , nums : List[int ], k : int , t : int ) -> bool :
72
+ for i in range (len (nums)):
73
+ for j in range (i + 1 , min (len (nums), i + k + 1 )):
74
+ if abs (nums[i] - nums[j]) <= t:
75
+ return True
76
+ return False
77
+ ```
78
+
79
+ ** 复杂度分析**
80
+
81
+ - 时间复杂度:$O(N ^ 2)$
82
+ - 空间复杂度:$O(1)$
83
+
84
+ ## 分桶 (通过)
85
+
86
+ ### 思路
39
87
40
88
这道题是 [ 219. 存在重复元素 II] ( https://github.com/azl397985856/leetcode/blob/master/problems/219.contains-duplicate-ii.md ) 的进阶版。那道题的条件是 ` nums[i] == nums[j] ` , 而这道题则更加宽泛,是` nums [i] 和 nums [j] 的差的绝对值小于等于 t ` 。
41
89
@@ -53,23 +101,36 @@ https://leetcode-cn.com/problems/contains-duplicate-iii/
53
101
54
102
另外由于题目限定是索引差小于等于 k,因此我们可以固定一个窗口大小为 k 的滑动窗口,每次都仅处理窗口内的元素,这样可以保证桶内的数任意两个数都满足** 索引之差的绝对值小于等于 k** 。 因此我们需要清除哈希表中过期(不在窗口内)的信息。
55
103
56
- ## 关键点
104
+ 具体算法:
105
+
106
+ - 我们将数据分到 M 个桶 中。
107
+ - 每个数字 nums[ i] 都被我们分配到一个桶中
108
+ - 分配的依据就是 nums[ i] // (t + 1)
109
+ - 这样相邻桶内的数字最多相差` 2 * t + 1 `
110
+ - 不相邻的桶一定不满足相差小于等于 t
111
+ - 同一个桶内的数字最多相差` t `
112
+
113
+ 1 . 因此如果命中同一个桶内,那么直接返回 True
114
+ 2 . 如果命中相邻桶,我们再判断一下是否满足 相差 <= t
115
+ 3 . 否则返回 False
116
+
117
+ 需要注意的是,由于题目有索引相差 k 的要求,因此要维护一个大小为 k 的窗口,定期清除桶中` 过期 ` 的数字。
118
+
119
+ ### 关键点
57
120
58
121
- 分桶排序思想的应用
59
122
60
- ## 代码
123
+ ### 代码
61
124
62
- - 语言支持:Python3
125
+ 我们使用哈希表来模拟桶,key 就是桶号,value 就是数字本身。
63
126
64
- Python3 Code :
127
+ Python 3 :
65
128
66
129
``` python
67
-
68
130
class Solution :
69
131
def containsNearbyAlmostDuplicate (self , nums : List[int ], k : int , t : int ) -> bool :
70
132
bucket = dict ()
71
- if t < 0 :
72
- return False
133
+ if t < 0 : return False
73
134
for i in range (len (nums)):
74
135
nth = nums[i] // (t + 1 )
75
136
if nth in bucket:
@@ -79,11 +140,41 @@ class Solution:
79
140
if nth + 1 in bucket and abs (nums[i] - bucket[nth + 1 ]) <= t:
80
141
return True
81
142
bucket[nth] = nums[i]
82
- # 如果数组有相同的数会有影响么?答案是不会,因为如果有相同的数,我们直接就会在前面返回 true 了。
83
- if i >= k:
84
- bucket.pop(nums[i - k] // (t + 1 ))
143
+ if i >= k: bucket.pop(nums[i - k] // (t + 1 ))
85
144
return False
145
+ ```
86
146
147
+ C++
148
+
149
+ ``` c++
150
+ class Solution {
151
+ public:
152
+ bool containsNearbyAlmostDuplicate(vector<int >& nums, int k, int t) {
153
+ if(t<0) return false;
154
+ //t+1可能会溢出,所以要+ 1LL
155
+ long long mod = t + 1LL;
156
+ unordered_map<long long,long long> buck;
157
+ for(int i=0;i<nums.size();i++)
158
+ {
159
+ long long nth = nums[ i] / mod;
160
+ //可能nums[ i] 为负数,比如-4 / 5 以及 -4 / 5都等于0,所以负数要向下移动一位
161
+ if(nums[ i] < 0) nth--;
162
+ //这里要用find 不能直接[ ] ,因为可能本身存储的数字就为0
163
+ if(buck.find(nth)!=buck.end())
164
+ return true;
165
+ else if(buck.find(nth-1)!=buck.end() && abs(nums[ i] - buck[ nth-1] ) <= t)
166
+ return true;
167
+ else if(buck.find(nth+1)!=buck.end() && abs(nums[ i] - buck[ nth+1] ) <= t)
168
+ return true;
169
+ buck[ nth] = nums[ i] ;
170
+ if(i >= k)
171
+ {
172
+ buck.erase(nums[ i - k] / mod);
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+ };
87
178
```
88
179
89
180
**复杂度分析**
0 commit comments