LeetCode刷题: 【76】最小覆盖子串

本文介绍了一种解决字符串子串问题的有效算法——滑动窗口法,并通过LeetCode上的一道经典题目“最小覆盖子串”来详细阐述其原理与实现。文章提供了完整的Java代码示例,展示了如何利用哈希表优化搜索过程,找到包含特定字符集的最短子串。

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

1. 题目

给你一个字符串 S、一个字符串 T,请在字符串 S里面找出:包含 T所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:

如果 S 中不存这样的子串,则返回空字符串 ""
如果 S 中存在这样的子串,我们保证它是唯一的答案。

链接:https://leetcode-cn.com/problems/minimum-window-substring

2. 思路

(1) 对于这类求子串问题,首先想到的方法就是滑动窗口,即通过双指针先后遍历字符串,在遍历过程中对当前窗口进行判断,当满足条件时更新记录,直至遍历完成。
过程示例
(2) 那么如何在搜索过程中确定当前窗口是否满足条件呢?众所周知,hash表的查找速度是最快的,我们尝试使用hash表将目标字符和需求出现次数做一个映射,例如T=“AAABBC”,那么建立映射
MAP:{A:3, B:2, C:1},在头指针前进过程中,若头指针所指向元素存在于MAP中,则使对应元素映射值-1,当所有映射值小于零的时候(在满足条件之前可能有的映射值会变为负数,为缩短条件判断时间,采用一个变量记录归零值的数量,当该变量等于MAP的长度时,条件被满足),认为当前窗口符合条件,开始窗口收缩(尾指针开始追赶),尾指针指向元素存在于MAP中时,使映射值+1,当任意映射值大于零时,就获得了一个最小窗口。继续移动头指针,开始下一轮的搜索。

3. 代码

class Solution {
	public String minWindow(String s, String t) {

		if (s.length() == 0 || t.length() == 0) {
			return "";
		}

		// 建立映射计数
		Map<Character, Integer> temp = new HashMap<>();

		for (char c : t.toCharArray()) {
			temp.put(c, temp.getOrDefault(c, 0) + 1);
		}

		// 字符串转换为数组
		char[] ss = s.toCharArray();

		// 建立双指针
		int head = 0, tail = 0;

		// 记录最小宽度 以及当时尾指针位置
		int min = s.length();
		int mt = -1;

		// 开始搜索
		for (int size = temp.size(); head < s.length(); head++) {
			// 计数搜寻(头指针向后移动)
			if (temp.keySet().contains(ss[head])) {
				Integer num = temp.get(ss[head]);
				temp.put(ss[head], num - 1);
				if (num == 1)
					size--;
			}

			// 缩小范围(当窗口满足条件,尾指针开始追赶;不满足条件时停止追赶)
			if (size == 0) {
				do {
					if (temp.keySet().contains(ss[tail])) {
						Integer num = temp.get(ss[tail]) + 1;
						temp.put(ss[tail], num);
						if (num == 1)
							size++;
					}
					tail++;
				} while (size == 0);

				// 记录最小值
				if (head - tail + 1 < min) {
					mt = tail - 1;
					min = head - mt;
				}
			}
		}

		return mt == -1 ? "" : s.substring(mt, mt + min + 1);
	}
}

4. 复杂度

mT 的长度,nS 的长度

时间复杂度:O(m+n)
空间复杂度:O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值