0
点赞
收藏
分享

微信扫一扫

Java滑动窗口算法题目练习

滑动窗口算法是处理数组/字符串中子序列问题的高效方法,尤其适合解决“连续子元素”相关问题(如子数组、子串)。以下是几道经典的Java滑动窗口算法练习题,附带解题思路和代码实现,供你练习参考:

1. 无重复字符的最长子串(LeetCode 3)

题目:给定一个字符串 s,请你找出其中不含有重复字符的 最长子串 的长度。
示例
输入: s = "abcabcbb" → 输出: 3(解释: 因为无重复字符的最长子串是 "abc"

思路

  • 哈希集合 记录窗口内的字符,避免重复。
  • 左指针 left 和右指针 right 维护当前窗口 [left, right]
  • 右指针右移,若字符重复,则左指针右移并移除集合中对应字符,直到无重复。
  • 每次移动右指针时,更新最大长度。

代码

public int lengthOfLongestSubstring(String s) {
    Set<Character> set = new HashSet<>();
    int maxLen = 0;
    int left = 0;
    for (int right = 0; right < s.length(); right++) {
        char c = s.charAt(right);
        // 若字符重复,移动左指针直到无重复
        while (set.contains(c)) {
            set.remove(s.charAt(left));
            left++;
        }
        set.add(c);
        // 更新最大长度
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

2. 长度最小的子数组(LeetCode 209)

题目:给定一个含有 n 个正整数的数组和一个正整数 target,找出该数组中满足其和 ≥ target 的长度最小的 连续子数组,并返回其长度。若不存在,返回 0
示例
输入: target = 7, nums = [2,3,1,2,4,3] → 输出: 2(解释: 子数组 [4,3] 的和为7)

思路

  • 滑动窗口求和,右指针扩展窗口,左指针收缩窗口以寻找最小长度。
  • 当窗口和 ≥ target 时,尝试左移左指针,缩小窗口并更新最小长度。

代码

public int minSubArrayLen(int target, int[] nums) {
    int minLen = Integer.MAX_VALUE;
    int sum = 0;
    int left = 0;
    for (int right = 0; right < nums.length; right++) {
        sum += nums[right];
        // 当和满足条件时,收缩左指针
        while (sum >= target) {
            minLen = Math.min(minLen, right - left + 1);
            sum -= nums[left];
            left++;
        }
    }
    return minLen == Integer.MAX_VALUE ? 0 : minLen;
}

3. 滑动窗口最大值(LeetCode 239)

题目:给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
示例
输入: nums = [1,3,-1,-3,5,3,6,7], k = 3 → 输出: [3,3,5,5,6,7]

思路

  • 双端队列(Deque) 存储窗口内元素的 索引,保持队列中元素对应的数值 单调递减
  • 右指针移动时,移除队列中所有小于当前元素的索引(它们不可能是最大值),再加入当前索引。
  • 左指针移动时,若队首索引超出窗口范围,移除队首。
  • 每次右指针移动到窗口末尾时,队首即为当前窗口的最大值。

代码

public int[] maxSlidingWindow(int[] nums, int k) {
    if (nums == null || nums.length == 0) return new int[0];
    int[] res = new int[nums.length - k + 1];
    Deque<Integer> deque = new LinkedList<>(); // 存储索引,保持数值递减
    int index = 0;

    for (int right = 0; right < nums.length; right++) {
        // 移除队列中小于当前元素的索引(它们不可能是最大值)
        while (!deque.isEmpty() && nums[right] >= nums[deque.peekLast()]) {
            deque.pollLast();
        }
        deque.offerLast(right);

        // 移除窗口外的索引(左边界为 right - k + 1)
        if (deque.peekFirst() <= right - k) {
            deque.pollFirst();
        }

        // 当窗口大小达到 k 时,记录最大值(队首)
        if (right >= k - 1) {
            res[index++] = nums[deque.peekFirst()];
        }
    }
    return res;
}

4. 找到字符串中所有字母异位词(LeetCode 438)

题目:给定两个字符串 sp,找到 s 中所有 p异位词 的子串,返回这些子串的起始索引。异位词指由相同字母重排列形成的字符串(包括相同的字符串)。
示例
输入: s = "cbaebabacd", p = "abc" → 输出: [0,6](解释: 子串 s[0..2]="cba"s[6..8]="bac"p 的异位词)

思路

  • 哈希表(或数组) 记录 p 中字符的频率,再用滑动窗口匹配 s 中对应长度的子串频率。
  • 窗口大小固定为 p 的长度,右指针移动时更新窗口内字符频率,左指针同步移动以保持窗口大小。
  • 若窗口内频率与 p 完全匹配,则记录左指针索引。

代码

public List<Integer> findAnagrams(String s, String p) {
    List<Integer> res = new ArrayList<>();
    int sLen = s.length(), pLen = p.length();
    if (sLen < pLen) return res;

    int[] pCount = new int[26]; // 记录p中字符频率
    int[] sCount = new int[26]; // 记录窗口中字符频率

    // 初始化p的频率和s的初始窗口频率
    for (int i = 0; i < pLen; i++) {
        pCount[p.charAt(i) - 'a']++;
        sCount[s.charAt(i) - 'a']++;
    }

    // 检查初始窗口是否匹配
    if (Arrays.equals(pCount, sCount)) {
        res.add(0);
    }

    // 滑动窗口(右指针从pLen开始)
    for (int right = pLen; right < sLen; right++) {
        // 加入右字符,移除左字符(保持窗口大小为pLen)
        sCount[s.charAt(right) - 'a']++;
        sCount[s.charAt(right - pLen) - 'a']--;

        // 若频率匹配,记录左指针(right - pLen + 1)
        if (Arrays.equals(pCount, sCount)) {
            res.add(right - pLen + 1);
        }
    }
    return res;
}

总结

滑动窗口算法的核心是通过 双指针(左右指针) 维护一个动态窗口,根据问题条件扩展或收缩窗口,从而在 O(n) 时间复杂度内解决问题(避免暴力法的O(n²))。练习时需注意:

  • 窗口是“连续的”,适用于子数组/子串问题。
  • 区分“固定窗口大小”(如第4题)和“可变窗口大小”(如第1、2题)的处理逻辑。
  • 合理使用辅助数据结构(哈希表、队列)优化窗口内元素的查询/更新效率。

可以尝试在LeetCode上提交这些代码,进一步熟悉滑动窗口的应用场景和细节处理~

举报

相关推荐

0 条评论