• 存在重复元素 II[简单]


    优质博文:IT-BLOG-CN

    一、题目

    给你一个整数数组nums和一个整数k,判断数组中是否存在两个不同的索引ij,满足nums[i] == nums[j]abs(i - j) <= k。如果存在,返回true;否则,返回false

    示例 1:
    输入:nums = [1,2,3,1], k = 3
    输出:true

    示例 2:
    输入:nums = [1,0,1,1], k = 1
    输出:true

    示例 3:
    输入:nums = [1,2,3,1,2,3], k = 2
    输出:false

    1 <= nums.length <= 105
    -109 <= nums[i] <= 109
    0 <= k <= 105

    二、代码

    【1】滑动窗口: 数组nums中的每个长度不超过k + 1滑动窗口,同一个滑动窗口中的任意两个下标差的绝对值不超过k。如果存在一个滑动窗口,其中有重复元素,则存在两个不同的下标ij满足nums[i] = nums[j]∣i−j∣ ≤ k。如果所有滑动窗口中都没有重复元素,则不存在符合要求的下标。因此,只要遍历每个滑动窗口,判断滑动窗口中是否有重复元素即可。

    如果一个滑动窗口的结束下标是i,则该滑动窗口的开始下标是max⁡(0,i−k)。可以使用哈希集合存储滑动窗口中的元素。从左到右遍历数组nums,当遍历到下标i时,具体操作如下:
    1、如果i > k,则下标i − k − 1处的元素被移出滑动窗口,因此将nums[i−k−1]从哈希集合中删除;
    2、判断nums[i]是否在哈希集合中,如果在哈希集合中则在同一个滑动窗口中有重复元素,返回true,如果不在哈希集合中则将其加入哈希集合。
    当遍历结束时,如果所有滑动窗口中都没有重复元素,返回false

    class Solution {
        public boolean containsNearbyDuplicate(int[] nums, int k) {
            // 思想,采用滑动窗口的思想,定义两个指针,之间的最大距离为k,如果超过k,则进行下一次判断,慢指针向前一步;
            if (nums != null && nums.length == 0) {
                return false;
            }
    
            for (int i = 0; i < nums.length; i++) {
                for (int j = i + 1; (j <= i + k && j < nums.length); j++) {
                    if (nums[i] == nums[j]) {
                        return true;
                    }
                }
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    时间复杂度: O(n)其中n是数组nums的长度。需要遍历数组一次,对于每个元素,哈希集合的操作时间都是O(1)
    空间复杂度: O(k)其中k是判断重复元素时允许的下标差的绝对值的最大值。需要使用哈希集合存储滑动窗口中的元素,任意时刻滑动窗口中的元素个数最多为k+1个。

    【2】哈希表: 从左到右遍历数组nums,当遍历到下标i时,如果存在下标j使得nums[i]=nums[j],则当i−j≤k时即找到了两个符合要求的下标ji。如果在下标i之前存在多个元素都和nums[i]相等,为了判断是否存在满足nums[i]=nums[j]i−j≤k的下标j,应该在这些元素中寻找下标最大的元素,将最大下标记为j,判断i−j≤k是否成立。

    如果i−j≤k,则找到了两个符合要求的下标ji;如果i−j>k,则在下标i之前不存在任何元素满足与nums[i]相等且下标差的绝对值不超过k,当遍历到下标i时,如果在下标i之前存在与nums[i]相等的元素,应该在这些元素中寻找最大的下标j,判断i−j≤k是否成立。

    可以使用哈希表记录每个元素的最大下标。从左到右遍历数组nums,当遍历到下标i时,进行如下操作:
    1、如果哈希表中已经存在和nums[i]相等的元素且该元素在哈希表中记录的下标j满足i−j≤k,返回true
    2、将nums[i]和下标i存入哈希表,此时inums[i]的最大下标。
    上述两步操作的顺序不能改变,因为当遍历到下标i时,只能在下标i之前的元素中寻找与当前元素相等的元素及该元素的最大下标。当遍历结束时,如果没有遇到两个相等元素的下标差的绝对值不超过k,返回false

    class Solution {
        public boolean containsNearbyDuplicate(int[] nums, int k) {
            // 思想:通过hashmap[key=nums中的元素,value = 下表],每次判断元素是否存在,存在则获取下表与当前的元素进行比较;
            if (nums != null && nums.length == 0) {
                return false;
            }
            Map<Integer, Integer> map = new HashMap<>();
            for (int i = 0; i < nums.length; i++) {
                if (map.containsKey(nums[i]) && i - map.get(nums[i]) <= k) {
                    return true;
                }
                map.put(nums[i], i);
            } 
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    时间复杂度: O(n),其中n是数组nums的长度。需要遍历数组一次,对于每个元素,哈希表的操作时间都是O(1)
    空间复杂度: O(n),其中n是数组nums的长度。需要使用哈希表记录每个元素的最大下标,哈希表中的元素个数不会超过n

  • 相关阅读:
    【SG滤波】三阶滤波、五阶滤波、七阶滤波(Matlab代码实现)
    Scratch软件编程等级考试一级——20191221
    Zookeeper3:客户端命令
    百度百科人物创建要求是什么?
    数据结构绪论思维导图
    web项目相关问题
    我是如何一步步获取房东的WiFi后台管理密码的【社工思路】
    JS(二)数据类型,流程控制
    Vue 3 + TypeScript + jsplumb
    MyBatis 核心配置讲解(上)
  • 原文地址:https://blog.csdn.net/zhengzhaoyang122/article/details/134257010