leecode 解题总结:76. Minimum Window Substring

#include <iostream>
#include <stdio.h>
#include <vector>
#include <set>
//#include <map>
#include <unordered_map>//哈希map,防止超时
#include <string>
using namespace std;
/*
问题:
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

分析:这个是编程之美中,最短摘要生成问题的变体。
之前最短摘要生成是在一篇文章中找到能够包含字符串数组中所有单词的句子。
当初的解法是,首先找到:包含所有单词的窗口的起始位置beg,结束位置end
然后从当前包含的窗口中修改beg,移动到下一个单词,尝试继续寻找能够包含所有单词的窗口。

那么对应于这个问题:就是比较字符串S中字符是否和T中某个字符相等,
首次找到第一个相等字符,令beg=end=该位置;
后续如果继续找到相等字符,检查从beg位置到end位置,检查是否包含了字符串T中所有字符,如果包含,记录
窗口长度,并令beg=beg+1,然后重复上述过程
最关键的是:只要包含了,就一直beg++,直到不包含位置


输入:
ADOBECODEBANC(主串) ABC(待查找字符串)
ADOBECODEBANC ABCC
输出:
BANC
CODEBANC

关键:
1 整个逻辑是:
如果从beg到end不包含所有待查找字符,end++
只要包含,就不断减少beg,直到不包含(确保能减少摘要长度)
beg >= len就退出

2 超时了,超时的原因应该是map查找慢了,用unordered_map即哈希map加快查找速度
还是超时,需要设定两个哈希map比较是否包含
*/

class Solution {
public:
	//用哈希map快一些
	unordered_map<char , int> initMap(string& t)
	{
		unordered_map<char, int> charToTimes;
		if(t.empty())
		{
			return charToTimes;
		}
		int lenT = t.length();
		for(int i = 0 ; i < lenT ; i++)
		{
			if(charToTimes.find(t.at(i)) != charToTimes.end())
			{
				charToTimes[t.at(i)]++;
			}
			else
			{
				charToTimes[t.at(i)] = 1;
			}
		}
		return charToTimes;
	}

	bool isInclude(unordered_map<char , int>& correctCharToTimes , unordered_map<char , int> charToTimes )
	{
		//比较两个map是否相等,应该用正确的map中每个键到实际得到的map中查找,如果找不到,或字符次数不等,说明有问题
		typedef unordered_map<char, int>::iterator mapIter;
		for(mapIter it = correctCharToTimes.begin() ; it != correctCharToTimes.end() ; it++)
		{
			mapIter itFind = charToTimes.find(it->first);
			if(itFind == charToTimes.end())
			{
				return false;
			}
			//待查找字符出现次数比实际次数少就不可能
			else if(itFind->second < it->second)
			{
				return false;
			}
		}
		return true;
	}

    string minWindow(string s, string t) {
		//如果待查找字符串为空,主串为空,直接返回空字符串
		if(s.empty() && t.empty())
		{
			return s;
		}
		//如果主串为空,待查找字符串不空,肯定返回空
		else if(s.empty())
		{
			return s;
		}
		//主串不空,待查找字符串为空,找不到,返回为空
		else if(t.empty())
		{
			return t;
		}
		//如果被查找字符串长度 > 主串长度,不可能
		if(t.length() > s.length())
		{
			return "";
		}
		int len = s.length();
        int beg = 0;
		int end = 0;
		int i = 0;
		bool isFirstFind = true;
		char value;
		int lenT = t.length();
		unordered_map<char , int> correctCharToTimes = initMap(t);//统计数组,用于确定被查找字符串中每个字符出现次数,初始化为0
		unordered_map<char , int> charToTimes;
		int minDis = INT_MAX;
		int realBeg = -1;
		int realEnd = -1;
		while(end < len)
		{
			value = s.at(end);
			//判断当前字符是否在模式串中,如果不在肯定不可能包含
			if(correctCharToTimes.find(value) == correctCharToTimes.end())
			{
				end++;
			}
			else
			{
				if(charToTimes.find(value) != charToTimes.end())
				{
					charToTimes[value]++;
				}
				else
				{
					charToTimes[value] = 1;
				}
				//如果不包含,就累加
				//if(!isInclude(correctCharToTimes , s, beg , end ))
				if(!isInclude(correctCharToTimes ,charToTimes ))
				{
					end++;
					continue;
				}
				//易错,判断从beg到end位置是否包含了T,包含了就令beg++,并,来减少摘要长度
				//while(isInclude(correctCharToTimes , s, beg , end ))
				while(isInclude(correctCharToTimes , charToTimes ))
				{
					if(end - beg < minDis)
					{
						minDis = end - beg;
						realBeg = beg;
						realEnd = end;
					}
					//令之前beg位置的字符次数减少
					if(charToTimes.find(s.at(beg)) != charToTimes.end())
					{
						charToTimes[s.at(beg)]--;
					}
					beg++;
				}
				end++;//易错,这里移动到下一个元素
			}
		}
		//没有找到
		if(realBeg == -1 && realEnd == -1)
		{
			return "";
		}
		else
		{
			string result = s.substr(realBeg , realEnd - realBeg + 1);
			return result;
		}
    }
};

void process()
{
	 string str;
	 string pattern;
	 Solution solution;
	 while(cin >> str >> pattern )
	 {
		 string result = solution.minWindow(str , pattern);
		 cout << result << endl;
	 }
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值