zoukankan      html  css  js  c++  java
  • 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);
        }
        }
    };
     
     
     
     
     
  • 相关阅读:
    114.完全背包【恰好装满完全背包
    整数划分类型题目
    三目运算符
    关于 xk 的位数。
    多重背包二进制原理拆分问题
    2016.4.2 讲课笔记(动态规划)
    二叉树(2)二叉树创建的3种方法,二叉树的递归遍历,二叉树的销毁
    二叉树(1)已知某2种排序方式,创建这个二叉树并按第3种方式排序
    C++知识点总结(二)
    5款优秀的开源克隆软件
  • 原文地址:https://www.cnblogs.com/Tang-tangt/p/9038033.html
Copyright © 2011-2022 走看看