每日一题--220. 存在重复元素 III

题目描述(题目链接

给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。
如果存在则返回 true,不存在返回 false。

输入:nums = [1,2,3,1], k = 3, t = 0
输出:true

滑动窗口&二分(红黑树)

算法步骤

存储结构: TreeSet。
核心思想: 对于nums[i],用TreeSet(即红黑树)存储下标在[max(0,i-k),i-1]范围的数,红黑树是一个有序的结构

  1. 遍历数组,每次都找到当前红黑树中<=nums[i]的最大值和>=nums[i]的最小值(即找到最靠近nums[i]的两个数) –红黑树的查找操作
  2. 比较这两个数是否满足abs(nums[i] - nums[j]) <= t ,若满足直接返回true,不满足继续执行
  3. 将nums[i]加入到红黑树中 –红黑树的添加操作
  4. 删除不在[max(0,i-k),i-1]范围中的数(即nums[i-k],若存在的话) –红黑树的删除操作
对应代码
class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
       TreeSet<Long> knums = new TreeSet<Long>();
       for(int i=0;i<nums.length;i++){
           Long u = Long.valueOf(nums[i]);   //int转long
           Long l = knums.floor(u);   //<=nums[i]的最大值
           Long r = knums.ceiling(u);  //>=nums[i]的最小值
           if(l!=null&&(u-l)<=t) return true;
           if(r!=null&&(r-u)<=t) return true;
           knums.add(u);  //添加
           if(i>=k) knums.remove(Long.valueOf(nums[i-k]));//由于红黑树有序,这里不能直接删除第一个
       }
       return false;
    }
}

桶排序

算法步骤

存储结构: Hashmap。
核心思想: 对于nums[i],用Hashmap存储的是下标在[max(0,i-k),i-1]范围的数。用Hashmap中的每个<key,value>来表示一个桶,key是桶的编号,value是桶里存储的值,桶的大小为t+1。这样相差绝对值<=t的值只可能在:同一个桶里(肯定满足),前后相邻的两个桶里(可能满足)

  1. 遍历数组,获得nums[i]的编号
  2. 查询该编号对应的桶里是否有值,若有,直接返回true
  3. 若没有,查询相邻两个桶里的值是否满足相差绝对值<=t,若有,返回true
  4. 若没有,将该值加进桶里
  5. 删除不在[max(0,i-k),i-1]范围中的数(即nums[i-k],若存在的话)

示例:nums = [1,5,9,1,5,9], k = 2, t = 3
在这里插入图片描述

代码
class Solution {
    long size;
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        int n = nums.length;
        Map<Long, Long> map = new HashMap<>();
        size = t + 1L;   //int转long
        for (int i = 0; i < n; i++) {
            long u = nums[i] * 1L;
            long idx = getIdx(u);
            // 目标桶已存在(桶不为空),说明前面已有 [u - t, u + t] 范围的数字
            if (map.containsKey(idx)) return true;
            // 检查相邻的桶
            long l = idx - 1, r = idx + 1;
            if (map.containsKey(l) && u - map.get(l) <= t) return true;
            if (map.containsKey(r) && map.get(r) - u <= t) return true;
            // 建立目标桶
            map.put(idx, u);
            // 移除下标范围不在 [max(0, i - k), i) 内的桶
            if (i >= k) map.remove(getIdx(nums[i - k] * 1L));
        }
        return false;
    }
    long getIdx(long u) {
        return u >= 0 ? u / size : ((u + 1) / size) - 1;
    }
}

参考题解

题解绝绝子

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值