Leetcode第76题

Leetcode第76题

题目

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

注意

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

思路:

  • 我们可以用滑动窗口来解决这个问题。
  • 由于字符串 t 要统计重复字符,所以可以用HashMap来保存 t 中的字符及个数,用另一个HashMap来动态存储滑动窗口中的有效字符(即t中出现过的字符)及个数,然后比较两个HashMap,找到最短的子字符串。

代码:

import java.util.HashMap;
import java.util.Map;

/*
 * @lc app=leetcode.cn id=76 lang=java
 *
 * [76] 最小覆盖子串
 */

// @lc code=start
class Solution
{
    
    
    public String minWindow(String s, String t)
    {
    
    
        // 动态的保存滑动窗口中的有效字符(t中包含的字符)及其个数
        Map<Character, Integer> sMap = new HashMap<>();
        // 保存t中的字符及其个数
        Map<Character, Integer> tMap = new HashMap<>();
        // 滑动窗口的左指针
        int left = 0;
        // 记录最优解的左边界
        int ansLeft = 0;
        // 临时保存map中的key
        Character key;
        // 临时保存map中的value
        Integer value;
        // 记录滑动窗口的最小长度,即最短的子序列
        int minLen = Integer.MAX_VALUE;
        // 首先把t字符串中所有字符都取出来,计算每个字符的个数,存放入map中
        for (int i = 0; i < t.length(); i++)
        {
    
    
            key = t.charAt(i);
            if (tMap.get(key) != null)
            {
    
    
                value = tMap.get(key);
                tMap.put(key, value + 1);
            }
            else
            {
    
    
                tMap.put(key, 1);
            }
        }
        // right为滑动窗口的右指针
        for (int right = 0; right < s.length(); right++)
        {
    
    
            key = s.charAt(right);
            // 如果右指针指向的字符是t中的某个字符,那么就把这个字符在sMap中加1
            if (tMap.containsKey(key))
            {
    
    
                if (sMap.get(key) != null)
                {
    
    
                    value = sMap.get(key);
                    sMap.put(key, value + 1);
                }
                else
                {
    
    
                    sMap.put(key, 1);
                }
            }
            // 比较滑动窗口sMap中的有效字符及个数是否 >= tMap中的字符个数
            while (compareMap(sMap, tMap))
            {
    
    
                // 这里为了减少无效字符的判断次数,直接将左指针指向滑动窗口中的最左边的有效字符
                key = s.charAt(left);
                while (!tMap.containsKey(key))
                {
    
    
                    left++;
                    key = s.charAt(left);
                }
                // while循环完,此时left指向的key是一个有效的字符
                // 取一个最短的符合要求的子序列
                if (minLen > right - left + 1)
                {
    
    
                    minLen = right - left + 1;
                    ansLeft = left;
                }
                // 将left向左移动,缩小窗口的范围,判断是否仍然符合要求
                value = sMap.get(key);
                sMap.put(key, value - 1);
                left++;
            }
        }
        return minLen != Integer.MAX_VALUE ? s.substring(ansLeft, ansLeft + minLen) : "";
    }

    // compare two map
    // 比较滑动窗口sMap中的有效字符及个数是否 >= tMap中的字符个数
    public boolean compareMap(Map<Character, Integer> sMap, Map<Character, Integer> tMap)
    {
    
    
        Character key;
        Integer value;
        for (Map.Entry<Character, Integer> entry : tMap.entrySet())
        {
    
    
            key = entry.getKey();
            value = entry.getValue();
            if (sMap.containsKey(key) && sMap.get(key) >= value)
            {
    
    

            }
            else
            {
    
    
                return false;
            }
        }
        return true;
    }
}

// @lc code=end

猜你喜欢

转载自blog.csdn.net/m0_59019651/article/details/119811673