LeetCode 219. Contains Duplicate II

题目

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...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值