Minimum Window Substring 最小覆盖子串算法

转载:https://blog.csdn.net/fly_yr/article/details/51134340

题目

 最小子串覆盖

给定一个字符串source和一个目标字符串target,在字符串source找到包括所有目标字符串字母的最小子串。

 注意事项

如果在source没有这样的子串,返回"",如果有多个这样的子串,返回长度最小的子串。

说明

在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?

——不需要。

样例

给出source = "ADOBECODEBANC"target = "ABC" 满足要求的解  "BANC"

挑战

要求时间复杂度为O(n)

分析

采用哈希的思想,记录字母出现次数。
大小写字母的ASCII码不大于256,这样array['A']=3指A出现3次,array['B']=1指B出现了一次,以此类推,不能用常规意义上的定义array[0]=3表示A出现3次,这样就多了一层映射!故而数组的长度设置为256即可存放所有的字母。

首先预处理target,用256大小的整数数组tHash存储里面每个char出现的个数;
然后给定两个指标beg和end,一个移动start,也用一个256长的整数数组sHash记录从beg到end的这段字符串里面每个char出现的个数。如果sHash大于等于tHash,也就是说sHash里的每一位大于等于tHash里相应位置的值,找到当前start位置,为符合要求子串的起点,记录当前beg和end的长度,如果比已经记录的小,那么我们就选这个位最小窗口。记录beg和end。然后让start往前走一位。寻找下一个子串。

/*
32 最小子串覆盖
给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串。
如果在source中没有这样的子串,返回"",如果有多个这样的子串,返回长度最小的子串。
说明
在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?
——不需要。
样例
给出source = "ADOBECODEBANC",target = "ABC" 满足要求的解  "BANC"
*/
 
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
 
using namespace std;
 
class Solution {
public:
	/**
	* @param source: A string
	* @param target: A string
	* @return: A string denote the minimum window
	*          Return "" if there is no such a string
	*/
	string minWindow(string &source, string &target) {
		// write your code here
		if (source.empty() || target.empty())
			return "";
 
		int sLen = source.length(), tLen = target.length();
		vector<int> sHash(256, 0), tHash(256, 0);
		/*建立源串的映射,存储每个字符的出现次数*/
		for (int i = 0; i < tLen; ++i)
		{
			++tHash[target[i]];
		}//for
 
		/*记录符合要求的子串的位置,以及找到的字符个数*/
		int beg = -1, end = sLen, found = 0, minLen = sLen;
		for (int i = 0, start = i; i < sLen; ++i)
		{
			++sHash[source[i]];
			/*更新当前找到的字符个数*/
			if (sHash[source[i]] <= tHash[source[i]])
				++found;
			/*判断是否找到所有字符*/
			if (found == tLen)
			{
				/*将源串开头未出现在目标串的字符跳过*/
				while (start < i && sHash[source[start]] > tHash[source[start]])
				{
					--sHash[source[start]];
					++start;
				}//while
				/*找到符合要求子串的首尾位置start 与 i*/
				if (i - start < minLen)
				{
					minLen = i - start;
					beg = start;
					end = i;
				}//if
				/*跳过该子串的开头位置,寻找下一个子串*/
				--sHash[source[start++]];
				--found;
			}//if
		}//for
 
		/*如果beg值为-1,说明不存在这样的子串*/
		if (beg == -1)
			return "";
		else
			return source.substr(beg, end - beg + 1);
	}
};
 
int main()
{
	Solution s;
	string source = "ADOBECODEBANC", target = "BANC";
 
	cout << s.minWindow(source, target) << endl;
 
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值