思路一: set。始终保持set的size小于等于k。遍历数组,如果数组中有这个数字,返回true;如果没有则加入set,然后这时要check set的size是否小于等于k,大于k的话则要删除最早加入set的数字。这边我们需要明白的一点是set中的数字都是数组中连续的数字,最多只保存k个数字,所以当新来一个数字的时候,此时set中的数字就是这个新来的数字的前k(也可能比k少)个数字,那么如果set中有和新来的数字相同的数字,则我们找到重复。下面展示代码:
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Set<Integer> set = new HashSet<>();
for(int i = 0; i < nums.length; i++){
if(set.contains(nums[i]))
return true;
set.add(nums[i]);
if(set.size() > k)
set.remove(nums[i - k]);
}
return false;
}
}
思路二: map。遍历数组,key是nums[i],value是i。这边很巧妙的用到map的put方法。如果key存在的话,说明我们找到了重复,此时就要check两者下标距离是否小于等于k。怎么check呢?则是利用put的返回值,若key相同的话,新的value就代替老的value,并且回返回老的value,这个老的value其实就是那个相同的老数字的下标,那么此时我们就有了两个数的下标,简单check一下就好。这边要注意的是如果找到了重复,但是check之后并不满足小于等于k的条件,那么此时我们已经put进新数字了,原来的老数字就不见了(存在map中的是新数字的信息),那这边会不会引起麻烦呢,玩意之后的数字有和删掉的这个老数字匹配上的呢?其实这边不用担心这个问题,删掉就删掉了,因为这个数字已经没用了。为什么呢?因为之后来的数字只可能下标越来越大,你前面的都不行了,还指望后面的数字满足条件?下面展示这个思路的两种实现,其实是一样的:
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
if(map.containsKey(nums[i])){
if(i - map.get(nums[i]) <= k)
return true;
}
map.put(nums[i],i);
}
return false;
}
}
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i = 0; i < nums.length; i++) {
Integer old = map.put(nums[i], i);
if(ord != null && i - old <= k) {
return true;
}
}
return false;
}
总结:
- hashmap和hashtable的区别:hashmap是hashtable的轻量级实现,所以是线程不安全的,但是效率更高。hashtable是线程安全的。
- map.put() This method returns returns previous value associated with the key if present, else return -1.