题目:
Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.
Example 1:
Input: nums = [1,2,3,1], k = 3 Output: true
Example 2:
Input: nums = [1,0,1,1], k = 1 Output: true
Example 3:
Input: nums = [1,2,3,1,2,3], k = 2 Output: false
2022.10.25 Java
思路挺简单的,就是很直观地用hashmap记录val和对应的index,然后计算index之差是否<=给定的k。刚开始想多了还算了min……嗯……是我想多了。
Runtime: 37 ms, faster than 78.77% of Java online submissions for Contains Duplicate II.
Memory Usage: 94.2 MB, less than 33.01% of Java online submissions for Contains Duplicate II.
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer, Integer> valToIndex = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (valToIndex.containsKey(nums[i])) {
int diff = i - valToIndex.get(nums[i]);
if (diff <= k) {
return true;
}
}
valToIndex.put(nums[i], i);
}
return false;
}
}
然后看到了用sliding window的思想,用set解决的,非常巧妙但是难想。 刚开始想着就每次取长度为k的subarray往set里放,如果重复了就return true否则return false,结果提交的时候发现不能cover length == k这种情况,因为根本进不去for loop……最后还是只能把set写在外面,就用这一个set每次remove和add element。在remove和add的时候要注意边界条件,注意题目说index <= k,which means set里的element个数最多是k + 1。所以两种判断方法:
1. set里有k + 1个元素了,此时i > k,那么就要先从set里remove掉第一个(i - k - 1)以后,看当前nums[i]是否在剩下的k个元素里出现。
Runtime: 51 ms, faster than 57.12% of Java online submissions for Contains Duplicate II.
Memory Usage: 78.2 MB, less than 66.66% of Java online submissions for Contains Duplicate II.
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
// if already has k + 1 elements, remove the first one before checking
if (i > k) {
set.remove(nums[i - k - 1]);
}
// this is checking for previous k elements plus the to-be-added oen
if (set.contains(nums[i])) {
return true;
}
set.add(nums[i]);
}
return false;
}
}
2. set里有k个元素了,此时i >= k,那么就要先判断当前nums[i]是否在这i个元素里出现,然后再把nums[i]加进去,把第一个remove掉(i - k)。但是这种方法好像有个bug,就是k == 0的情况下,它就退化成了判断整个数组里是否有duplicated,但其实k == 0永远都只能return false……只能强行在前面加一句if了。
Runtime: 47 ms, faster than 64.22% of Java online submissions for Contains Duplicate II.
Memory Usage: 82.5 MB, less than 55.95% of Java online submissions for Contains Duplicate II.
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
if (k == 0) {
return false;
}
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
return true;
}
if (i >= k) {
set.remove(nums[i - k]); // remove the first from sliding window if reaching maximum size
}
set.add(nums[i]);
}
return false;
}
}
这道题和之前那道的不一样之处就在于,这道题要求两个重复的数字的下标之差不超过k。既然对下标有要求,那就不能用sort了,只能用hash map存放每个数字及其对应的下标,然后对比两个相同数字的下标之差。需要注意的一点就是,如果一个数字重复出现了超过两次,而前两次相差超过k的话,需要更新这个数字在hash map中的下标,因为后面还可能有满足条件的下标,这里差一点被坑了,是原题给出的test case2发现的。时间复杂度O(n),24ms,95.37%,空间复杂度看底层unordered_map了,15.3M,82.35%,整体感觉还是性能挺好的:
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> indexes;
for (int i = 0; i < nums.size(); i++) {
if (indexes.count(nums[i]) != 0) {
if (i - indexes[nums[i]] <= k) {
return true;
}
}
indexes[nums[i]] = i;
}
return false;
}
};
再次复习了unordered_map的插入和查找:
插入可以通过直接赋值来完成:hash[key] = value;
查找是否出现可以使用计数来完成:hash.count(key)返回的是key在这个HashMap中的key中出现的次数。
还有一种可以直接用unordered_set的方法,好像比较复杂,不想看了,贴链接:Loading...