【leetcode】76. 最小覆盖子串(滑动窗口)

滑动窗口问题的通用解题思路:
https://labuladong.gitbook.io/algo/di-ling-zhang-bi-du-xi-lie/hua-dong-chuang-kou-ji-qiao-jin-jie

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

示例:

输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”

说明:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

注意事项:

  1. s可能会比t还要小。
  2. t中可能会有重复的数字
  3. 在比较是否符合条件时,需要判断的是cur中的字符数量小于目标的字符串,而不是不等于。
s = "aaaaaabbbccccdd"
t = "abcd"

这种条件就是需要包含多个b和c,如果按照!=来判断是肯定不行的

效率托底,但总比暴力枚举要好一些


解题思路:
维护两个指针,两个指针构成了一个结果的窗口,从左向右滑动
滑动终止条件是右侧指针滑到最右侧时。
每次向右滑动一次,将当前right指针指向的字符添加到hash表中,计数。
同时左侧指针也要判断是否向右滑动,当左侧指针指向的字符不在目标字符串中,或者当前的窗口中的当前字符的数量大于目标字符串中当前字符的数量时,向右侧滑动

typedef unordered_map<char, int> umci;
// 滑动窗口问题
// https://leetcode-cn.com/problems/minimum-window-substring/
// 76. 最小覆盖子串

// 还要考虑s的长度比t还要小。
// t中有重复的字符改怎么处理
string minWindow(string s, string t) {
	if (s.size() < t.size())
		return "";

	int l = 0, r = 0;
	umci target;
	umci cur;
	vector<std::pair<int, int>> res; // 存放l r的结果

	for (int i = 0; i < t.size(); i++)
	{
		if (target.find(t[i]) != target.cend())
		{
			target[t[i]] = target[t[i]] + 1;
		}
		else
		{
			target.insert(make_pair(t[i], 1));
		}
	}

	while (r < s.size())
	{
		char c = s[r];
		umci::const_iterator it = target.find(c);
		if (it != target.cend())
		{
			cur[c] = cur[c] + 1;
		}
		r++;

		while (l < r)
		{
			// 2种情况,l会向右移动,1:当前字符不是t中的,2:当前字符是t中的,但是已经重复了
			char cl = s[l];
			if (target.find(cl) != target.cend())
			{
				int count = cur[cl];
				if (count > target[cl])
				{
					l++;
					cur[cl] = count - 1;
				}
				else
				{
					break; // 防止死循环
				}
			}
			else
			{
				l++;
			}
		}

		if (cur.size() == target.size())
		{
			// 还需要判断重复的字符
			bool ok = true;
			for (auto it = target.cbegin(); it != target.cend(); it++)
			{
				if (cur[it->first] < it->second) // 注意这里是小于
				{
					ok = false;
					break;
				}
			}
			if (ok)
				res.push_back(make_pair(l, r));
		}
	}

	
	if (res.size() > 0)
	{
		int minIndex = 0;
		int curLen = s.size() + 1;

		for (int i = 0; i < res.size(); i++)
		{
			int lp = res[i].first;
			int rp = res[i].second;

			if (rp - lp < curLen)
			{
				curLen = rp - lp;
				minIndex = i;
			}
		}

		return s.assign(s, res[minIndex].first, res[minIndex].second - res[minIndex].first);
	}

	return "";
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值