java实现最小覆盖子串最后一个测试不通过

该博客讨论了如何使用Java解决LeetCode中的第76题——最小覆盖子串。作者指出,当字符串s是否包含字符串t的所有字符,即s="a"且t="aa"时,正确答案应为空字符串。在实现过程中,作者遇到了使用Map记录字符次数时,最后一个测试用例失败的问题,原因是Integer对象的缓存机制。为解决这个问题,作者建议在比较Map中值时使用equals方法而非直接比较。同时,提供了滑动窗口算法的代码框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

leetcode:76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

示例 2:

输入:s = "a", t = "a"
输出:"a"

提示:

1 <= s.length, t.length <= 105
s 和 t 由英文字母组成

误区:题目中所说意思为:在s中是否包含 t 中的所有字符,即当 s = “a”, t = “aa” 时,返回的应为 “”

遇到的问题:leetcode 76. 最小覆盖子串 使用 java 中的 map 存储字符及对应的次数时,最后一个示例报错
在 Java 中用Map记录字母出现个数的写法,
最后一个测试用例不能通过:
Integer是对象
Integer会缓存频繁使用的数值
数值范围为-128到127,在此范围内直接返回缓存值。
超过该范围就会new 一个对象。
解决方案为在比较 map 中对应键的值时,使用 equals 判断

代码

/**
使用滑动窗口,设置左右两个指针 right 和 left,滑动窗口为 [left, right) 一个用于「延伸」现有窗口
的 right 指针,和一个用于「收缩」窗口的 left 指针。
在任意时刻,只有一个指针运动,而另一个保持静止。我们在 s 上滑动窗口,通过移动 right 指针不断扩张窗口。
当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。

即先寻找可行解(包含 t 中所有字符,再不断优化)

*/
class Solution {
     public String minWindow(String s, String t) {
       // need 中的键是 t 中的所出现的字符,对应的值为字符出现的次数
       // window 中的键是在字符串 s 上查找时,滑动窗口中存在的 t 中的字符,值为该字符在窗口中的个数
        if (s == null || s.equals("") || t == null || t.equals("") || s.length() < t.length()) {
            return "";
        }
        Map<Character, Integer> need = new HashMap<>();
        Map<Character, Integer> window = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            need.put(c,need.getOrDefault(c, 0) + 1);
        }
        int left = 0, right = 0;
        int valid = 0;
        int start = 0, len = 100001;

        while (right < s.length()) {
            char c = s.charAt(right);
            right++;
            // 进行窗口内数据的一系列更新
            if (need.containsKey(c)) {
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (window.get(c).equals(need.get(c)))  {
                    valid++;
                }
            }
            // 判断左侧窗口是否需要收缩
            while (valid == need.size()) {
                // 更新最小覆盖子串
                if (right - left < len) {
                    start = left;
                    len = right - left;
                }
                // d 是将移出窗口的字符
                char d = s.charAt(left);
                left++;
                // 对窗口内数据进行一系列更新
                if (need.containsKey(d)) {
                    if (window.get(c).equals(need.get(c))) 
                        valid--;
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return len == 100001 ? "" : s.substring(start, len + start);  
    }
}

附:滑动窗口算法框架

void slideWindow(String s, String t) {
        Map<Character, Integer> need = new HashMap<>();
        Map<Character, Integer> window = new HashMap<>();

        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            need.put(c, need.getOrDefault(c, 0) + 1);
        }

        int left = 0, right = 0;
        int valid = 0;
        while (right < s.length()) {
            // c是将移入窗口的字符
            char c = s.charAt(right);
            // 右移窗口
            right++;
            // 进行窗口内数据的一系列更新
             ...
         

            /******* debug 输出位置 *******/
            System.out.format("window:[ %d, %d)", left, right);

            // 判断左侧窗口是否要收缩
            /**
            while (window needs shrink) {
             // d 是将溢出窗口的字符
             char d = s.charAt(left);
             // 左移窗口
             left++;
             // 进行窗口内数据的一系列更新
             ...
             }
             */
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值