题解 | #最小覆盖子串#

最小覆盖子串

https://www.nowcoder.com/practice/c466d480d20c4c7c9d322d12ca7955ac

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
    public String minWindow (String s, String t) {
        // write code here
          if (s == null || t == null || s.length() == 0 || t.length() == 0 || t.length() > s.length()) {
            return "";
        }

        // 记录t中每个字符出现的次数
        Map<Character, Integer> tFreq = new HashMap<>();
        for (char c : t.toCharArray()) {
            tFreq.put(c, tFreq.getOrDefault(c, 0) + 1);
        }

        int left = 0;  // 窗口的左边界
        int right = 0;  // 窗口的右边界
        int formed = 0;  // 记录窗口中包含t中字符的个数
        int required = tFreq.size();  // t中不同字符的个数
        Map<Character, Integer> windowFreq = new HashMap<>();  // 记录窗口中每个字符出现的次数

        int minLen = Integer.MAX_VALUE;  // 最小符合条件的子串的长度
        int minStart = -1;  // 最小符合条件的子串的起始位置

        while (right < s.length()) {
            char c = s.charAt(right);
            windowFreq.put(c, windowFreq.getOrDefault(c, 0) + 1);

            if (tFreq.containsKey(c) && windowFreq.get(c).intValue() == tFreq.get(c).intValue()) {
                formed++;
            }

            // 缩小窗口的范围,直到不再满足条件
            while (left <= right && formed == required) {
                c = s.charAt(left);

                if (right - left + 1 < minLen) {
                    minLen = right - left + 1;
                    minStart = left;
                }

                windowFreq.put(c, windowFreq.get(c) - 1);
                if (tFreq.containsKey(c) && windowFreq.get(c).intValue() < tFreq.get(c).intValue()) {
                    formed--;
                }

                left++;
            }

            right++;
        }

        if (minStart == -1) {
            return "";
        }

        return s.substring(minStart, minStart + minLen);
    }
}

这道题可以使用滑动窗口的方法来解决。定义两个指针left和right来表示窗口的左边界和右边界。

首先,我们先使用一个哈希表来记录字符串t中每个字符出现的次数,以便后面判断窗口中是否包含了t中的所有字符。

然后,使用双指针left和right来遍历字符串s。在每一步迭代中,先将right向右移动,直到窗口中包含了字符串t中的所有字符。

然后,再将left向右移动,缩小窗口的范围,找到最短的符合条件的子串。

最后,返回符合条件的子串。如果找不到,返回空字符串。

首先,我们创建一个哈希表tFreq来记录字符串t中每个字符出现的次数。然后,我们定义leftright作为窗口的左边界和右边界。

接下来,我们使用right向右移动,直到窗口中包含了字符串t中的所有字符。然后,我们使用left向右移动,缩小窗口的范围,找到最短的符合条件的子串。

在每一步迭代中,我们将每个位置的字符加入窗口中,并更新windowFreq的计数。如果该字符也出现在t中,并且窗口中该字符的数量等于tFreq中该字符的数量,我们将formed增加1。

当窗口中包含了t中的所有字符时,我们开始缩小窗口的范围。我们将left向右移动,剔除窗口的左边界字符,并根据需要更新formed的值。

当窗口不再满足条件时,我们再次将right向右移动,重新扩展窗口。

最后,我们得到了最短的符合条件的子串,我们可以根据minStartminLen来截取字符串s,返回结果。

时间复杂度为O(n),其中n是字符串s的长度。空间复杂度为O(n),用于存储哈希表和窗口内字符的计数。

注意,在上面的实现中,我们使用了windowFreq哈希表来记录窗口内字符的计数。在Java中,Map接口的方法getput的时间复杂度为O(1)。

全部评论

相关推荐

11-03 13:18
门头沟学院 Java
包行:平时怎么刷算法题的哇,字节的手撕听说都很难
字节跳动工作体验
点赞 评论 收藏
分享
12-13 14:51
已编辑
井冈山大学 算法工程师
龙虾x:算法比你强的没有你美,比你美的…..算了已经没有比你美的了
工作两年想退休了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务