题目描述
给定一个整数数组和一个整数 k
,判断数组中是否存在两个不同的索引 i
和 j
,使得 nums[i] = nums[j]
,并且 i
和 j
的差的 绝对值 至多为 k
。
样例
输入:nums = [1,2,3,1], k = 3
输出:true
输入:nums = [1,0,1,1], k = 1
输出:true
输入:nums = [1,2,3,1,2,3], k = 2
输出:false
算法1
(哈希表) $O(n)$
- 使用 unordered_map 哈希表,其关键字为整数,值为下标。
- 从头开始扫描数组,发现下标
i
的整数整数存在于哈希表中,且其下标和当前下标的差值小于等于k
,则返回true
;否则更新哈希表中该整数所对应的下标。 - 扫描完毕后返回
false
。
时间复杂度
unordered_map
的单次插入和查询时间复杂度为 $O(1)$,故总时间复杂度为 $O(n)$。
空间复杂度
- 需要额外 $O(n)$ 的空间存储哈希表。
C++ 代码
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> hash;
for (int i = 0; i < nums.size(); i++) {
if (hash.find(nums[i]) != hash.end())
if (i - hash[nums[i]] <= k)
return true;
hash[nums[i]] = i;
}
return false;
}
};
算法2
(集合判重) $O(n)$
- 使用 unordered_set,存放下标大于等于
i - k
的整数。 - 从头开始扫描数组,发现下标
i
的整数存在于集合中,则返回false
;然后将当前数字放入集合,在集合中删除下标为i - k
的数字。 - 扫描完毕后返回
false
。
时间复杂度
unordered_map
的单次插入和查询时间复杂度为 $O(1)$,故总时间复杂度为 $O(n)$。
空间复杂度
- 需要额外 $O(n)$ 的空间存储哈希表。
C++ 代码
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_set<int> v;
for (int i = 0; i < nums.size(); i++) {
if (v.find(nums[i]) != v.end())
return true;
v.insert(nums[i]);
if (i >= k)
v.erase(nums[i - k]);
}
return false;
}
};
请问一下为啥我在函数containsNearbyDuplicate()中开头加一句”if (k > 30000) return false;”以后,运行时间和运行占用的空间都大幅度提升了啊(leetcode上提交的结果)。
不太清楚你为什么要加这句话
我是看到LeetCode上的其他人的题解,发现他们都加了,我也不清楚为啥他们要加这句,但是加了效果就很好......
这句话算是cheat,可能测试数据里如果 k > 30000 就不会有 true 的情况。
做这种事情没有意义。
感谢解答,我以为这其中有超出我的理解范围的内容。
写错了,哈希是O(N)。望更正
感谢指出,已修正