32 最小子串覆盖

原题网址:https://www.lintcode.com/zh-cn/old/problem/minimum-window-substring/#

32. 最小子串覆盖 

 

讨论区 

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

 注意事项

如果在source中没有这样的子串,返回"",如果有多个这样的子串,返回起始位置最小的子串。

说明

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

——不需要。

样例

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

挑战 

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

标签 
 
 
思路:
 
使用哈希表,建立字符(索引)- 字符数量(值)的映射。
ASCII码表常用字符128个,建立两个容量为128的数组tcount[128]与scount[128],分别表示target中相应字符数量、source上的移动窗(子串)中相应字符数量,初始时两数组相应元素都为0;
遍历target,计算每个字符出现的次数,次数值存放在tcount【128】中;
定义int型变量begin = -1、end = source.size()、start = 0,found=0, 以及minLen = source.size(),分别代表移动窗起始位置、结束位置,窗口的移动索引,已经找到的目标串字符数量,窗口的最小长度(end-begin);
遍历source,如果source【i】对应字符的数量加1后小于或等于该字符在target中的数量,说明找到一个字符,则found++;
      若found等于target.size(),说明找到一个子串,这时就要确定移动窗的大小,即去掉前面那些无效的字符(target中没有但子串中有的字符),相当于确定移动窗起始位置。
                                      方法是移动start,如果scount[source[start]] > tcount[source[start]] ,说明是无效字符(两种情况:窗内存在该字符但目标中不存在,舍弃。另一种窗内该字符数量超过目标中数量,舍弃;),则scount[source[start]]--; start++;
                                      重复上述过程直到scount[source[start]] = tcount[source[start]],即找到了移动窗的起始位置。
                                      这时再判断当前窗长度是否小于minLen,小于则更新移动窗,即 begin = start;end = i;minLen = i-start;
       
                                      然后移动窗在源串上前移一位,注意舍弃起始位置字符(scount[source[start]]--; found--; start++;),继续寻找下一个子串;
 
循环结束后若begin==-1说明没找到子串,否则返回source.substr(begin,minLen+1);
 
AC代码:
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())
    {
        return "";
    }
    int ssize=source.size(); 
    int tsize=target.size();
    int tcount[128];
    int scount[128];//移动窗内相应字符的数量;
    for (int i=0;i<128;i++)
    {
        scount[i]=0;
        tcount[i]=0;
    }

    for (int j=0;j<tsize;j++)
    {
        tcount[target[j]]++;
    }

    int begin=-1,end=ssize,found=0,minLen=ssize;//初始化移动窗起始、终止位置、寻找过程中的子串累积长度,最小移动窗长度;
    for (int i=0,start=0;i<ssize;i++)
    {
        scount[source[i]]++;//遍历源串,如果这个字符的数量加1后不超过目标串中该字符的数量,则找到了一个匹配字符,found+1;
        if (scount[source[i]]<=tcount[source[i]])
        {
            found++;
        }

        if (found==tsize)//找到一个子串;
        {
            while(start<i&&scount[source[start]]>tcount[source[start]])//去掉无效字符,缩短移动窗长度;
            {                                                                 //两种情况:窗内存在该字符但目标中不存在,舍弃。另一种窗内该字符数量超过目标中数量,舍弃;
                scount[source[start]]--;//移动窗内去掉这个字符;
                start++;//继续向前判断;
            }
            //最后的结果是start对应的字符是目标中的某个字符;

            if (i-start<minLen)
            {
                minLen=i-start;
                begin=start;
                end=i;
            }

            //移动窗在源串上前移一位(舍弃起始字符),继续寻找子串;
            scount[source[start]]--;
            found--;
            start++;

        }
    }

    if (begin==-1)
    {
        return "";
    }
    else
    {
        return source.substr(begin,minLen+1);
    }
    }
};
 
 
 
 
 
原文地址:https://www.cnblogs.com/Tang-tangt/p/9038033.html