LeetCode Notes_#220_存在重复元素 III

LeetCode Notes_#220_存在重复元素 III

Contents

题目

在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。
如果存在则返回 true,不存在返回 false。

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

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

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

思路分析

方法1:暴力搜索

最简单的思路是暴力搜索,两层循环

  • 外层循环遍历数组中所有数字nums[i]
  • 内层循环遍历nums[i+1...i+k]范围内的所有数字,这是一个滑动窗口,计算nums[i]与窗口内所有数字的差值,如果有任何一个数字与nums[i]差值的绝对值不超过t,就返回true

但暴力搜索是无法通过的,leetcode上专门设置了一个k==10000的用例来使暴力搜索法超时。抖机灵的做法就是加上一句如下代码...这就是面向测试用例编程。

if(k==10000) return false;

开玩笑的,面试肯定不能这么写。

方法2:使用TreeSet(二叉搜索树)

使用java当中的TreeSet来保存数字。TreeSet用二叉搜索树实现,可以利用TreeSet里的ceiling/floor方法来找到窗口中是否有符合要求的值。详见代码。

解答

class Solution {
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        //TreeSet是特殊的Set,其中的元素不重复,且使用BST进行存储,可以快速查找ceiling,floor数
        TreeSet<Long> set = new TreeSet<>();
        for(int i = 0;i <= nums.length - 1;i++){
            //c是比nums[i]大的最小数
            Long c = set.ceiling((long)nums[i]);
            //如果c不大于nums[i] + t,就直接返回true
            //nums[i] + t可能超出int表示范围,所以要用long类型
            if(c != null && c <= (long)nums[i] + (long)t) return true;
            //s是比nums[i]小的最大数
            Long f = set.floor((long)nums[i]);
            //nums[i] - t可能超出int表示范围,所以要用long类型
            if(f != null && f >= (long)nums[i] - (long)t) return true;
            //将nums[i]加入set
            set.add((long)nums[i]);
            //窗口大小是k+1,当大小达到k+1时,就移除set当中窗口最左边的元素
            if(set.size() >= k + 1){
                set.remove((long)nums[i - k]);
            }
        }
        return false;
    }
}

复杂度分析

时间复杂度:O(nlog(min(n,k))),BST的搜索,插入,删除复杂度都是O(log(min(n,k)))
空间复杂度:O(min(n,k)),set的大小是min(n,k)

原文地址:https://www.cnblogs.com/Howfars/p/13515230.html