「力扣」第 220 题:220. 存在重复元素 III(滑动窗口)

题解地址:https://leetcode-cn.com/problems/contains-duplicate-iii/solution/hua-dong-chuang-kou-er-fen-sou-suo-shu-zhao-shang-/

给定一个整数数组,判断数组中是否有两个不同的索引 ij,使得 nums [i]nums [j] 的差的绝对值最大为 t,并且 ij 之间的差的绝对值最大为 ķ

示例 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

方法一:暴力解法

枚举所有长度小于等于 k + 1 的“下标对()”,只要发现 nums[i] - nums[j] 的绝对值小于 t ,就返回 true

Java 代码:

public class Solution {

    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        int len = nums.length;
        long a;
        long b;

        for (int i = 0; i < len; i++) {
            for (int j = i + 1; j < len && j <= i + k; j++) {
                a = nums[i];
                b = nums[j];
                if (Math.abs(a - b) <= t) {
                    return true;
                }
            }
        }
        return false;
    }
}

复杂度分析

  • 时间复杂度: O ( N 2 ) O(N^2) O(N2),这里数组的长度为 N N N,枚举可能的数对 ( i , j ) (i, j) (i,j)
  • 空间复杂度: O ( 1 ) O(1) O(1)

方法二:滑动窗口(以空间换时间)

题目意思翻译一下:在数组 nums[i] 中,在任意区间 [i, i + k] 里是否存在两个数的绝对值小于等于 t,即 ∣ n u m s [ i ] − n u m s [ j ] ∣ < = t |nums[i] - nums[j] | <= t nums[i]nums[j]<=t

等价于 n u m s [ i ] − n u m s [ j ] < = t nums[i] - nums[j] <= t nums[i]nums[j]<=t 并且 n u m s [ i ] − n u m s [ j ] > = − t nums[i] - nums[j] >= -t nums[i]nums[j]>=t

n u m s [ i ] < = t + n u m s [ j ] nums[i] <= t + nums[j] nums[i]<=t+nums[j] 并且 n u m s [ i ] > = n u m s [ j ] − t nums[i] >= nums[j] - t nums[i]>=nums[j]t

Java 代码:

import java.util.TreeSet;

public class Solution {

    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        // 滑动窗口结合查找表,此时滑动窗口即为查找表本身(控制查找表的大小即可控制窗口大小)
        TreeSet<Long> set = new TreeSet<>();
        for (int i = 0; i < nums.length; i++) {
            // 边添加边查找
            // 查找表中是否有大于等于 nums[i] - t 且小于等于 nums[i] + t 的值
            Long ceiling = set.ceiling((long) nums[i] - (long) t);
            if (ceiling != null && ceiling <= ((long) nums[i] + (long) t)) {
                return true;
            }
            // 添加后,控制查找表(窗口)大小,移除窗口最左边元素
            set.add((long) nums[i]);
            if (set.size() == k + 1) {
                set.remove((long) nums[i - k]);
            }
        }
        return false;
    }
}

另一种写法:在一开始就把多余的元素删除。

Java 代码:

import java.util.TreeSet;

public class Solution11 {

    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
        int len = nums.length;
        // 特判
        if (len == 0 || k <= 0 || t < 0) {
            return false;
        }

        TreeSet<Long> set = new TreeSet<>();

        for (int i = 0; i < len; i++) {
            if (i > k) {
                set.remove((long) nums[i - k - 1]);
            }

            Long ceiling = set.ceiling((long) nums[i] - (long) t);
            if (ceiling != null && ceiling <= (long) nums[i] + (long) t) {
                return true;
            }

            set.add((long) nums[i]);
        }
        return false;
    }
}

复杂度分析

  • 时间复杂度: O ( N log ⁡ K ) O(N\log K) O(NlogK),遍历数组使用 O ( N ) O(N) O(N),在遍历的同时向二叉搜索树中插入元素和移除元素的时间复杂度是 O ( log ⁡ K ) O(\log K) O(logK)
  • 空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(力扣)