最小子串覆盖
题目
给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串。
注意事项
如果在source中没有这样的子串,返回”“,如果有多个这样的子串,返回起始位置最小的子串。说明
在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?
——不需要。样例
给出source = “ADOBECODEBANC”,target = “ABC” 满足要求的解 “BANC”
挑战
要求时间复杂度为O(n)
题解
本题注意事项中翻译有误,不是返回起始位置最小的子串而是长度最短的子串。
首先对target进行处理,把每个字母的数量以ASCII码的值为地址存入targethash数组。再构建两个指针i,j对source进行遍历,同时将遍历得到的字母的数量计入sourcehash数组,如果不能做到子串覆盖则将j指针后移读入新字母,反之则将i指针后移并从sourcehash数组中减去相应的字母计数,同时比较和记录最小子串,直至遍历完毕。
以样例为例:
ADOBECODEBANC
a.当i=0时,sourcehash为空,显然不满足子串,则将j后移直至j=5时。此时sourcehash的计数为A=1,B=1,C=1,满足子串要求,此时最小子串为ADOBEC,长度为6。最后将A的计数减1,此时sourcehash的计数为A=0,B=1,C=1。
b.当i=1时,由于sourcehash不满足子串要求,则继续步骤a直至j=10。此时sourcehash的计数为A=1,B=2,C=1,最小子串为DOBECODEBA,长度为10。最后将D的计数减1,此时sourcehash的计数为A=1,B=2,C=1。
c.当i=2时,最小子串为OBECODEBA,直至i=6时,sourcehash的计数为A=1,B=2,C=0,将j继续向后移动至最后一位,sourcehash重新满足子串要求。再继续重复上述步骤可获取最小子串。
public class Solution
{
/**
* @param source:
* A string
* @param target:
* A string
* @return: A string denote the minimum window Return "" if there is no such
* a string
*/
public String minWindow(String Source, String Target)
{
int ans = Integer.MAX_VALUE;
String minStr = "";
int[] sourcehash = new int[256];
int[] targethash = new int[256];
initTargetHash(targethash, Target);
int j = 0, i = 0;
for (i = 0; i < Source.length(); i++)
{
while (!valid(sourcehash, targethash) && j < Source.length())
{
sourcehash[Source.charAt(j)]++;
j++;
}
if (valid(sourcehash, targethash) && ans > j - i)
{
ans = j - i;
minStr = Source.substring(i, j);
}
sourcehash[Source.charAt(i)]--;
}
return minStr;
}
private void initTargetHash(int[] targethash, String Target)
{
for (char ch : Target.toCharArray())
{
targethash[ch]++;
}
}
private boolean valid(int[] sourcehash, int[] targethash)
{
for (int i = 0; i < 256; i++)
{
if (targethash[i] > sourcehash[i])
{
return false;
}
}
return true;
}
}
Last Update 2016.9.26