• Lintcode--004(最小子串覆盖)


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

    注意事项

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

    说明

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

    ——不需要。

    样例

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

    标签 

     
     

    解题:这个题目关于最小子串覆盖,跟字符串匹配还是有区别的,所以不可以用KMP来求解。

    思路:

    采用哈希的思想,记录字母出现次数。

    【方法:可以定义一个整形数组,利用映射 map<char,int> m; 定义一个关联容器也可。】

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

    代码如下:

    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 slength=source.length(); //size()和length()都是返回字符串的长度,本质上没有区别;
            int tlength=target.length();
            
            int s[256],t[256];
            memset(s,0,sizeof(s));
            memset(t,0,sizeof(t));
            
            for(int i=0;i<target.length();i++){ //统计目标串中每个字符出现的次数;
                t[target[i]]++;
            }
            
            int beg = -1, end = slength, found = 0, minLen = slength;  //将最小长度先赋值为源字符串的长度;
            
            for(int i=0,start=0;i<source.length();i++){//注意变量start不要拼写错误!
                s[source[i]]++;
                // 如果加1后这个字符的数量不超过目标串中该字符的数量,则找到了一个匹配字符
                if(s[source[i]]<=t[source[i]]){ //比较源串中的字符是否在目标串中出现过;
                    found++;//更新出现的字符的个数;
                } //为了将目标字符串中出现的字符都包含!
                
                // 这一点很重要!!!//
                // 如果找到的匹配字符数(只是记录匹配的字符数量)等于目标串长度,说明找到了一个符合要求的子串 
                // 这一点很重要!!!//
                
                if(found==tlength){
                    //将开头没用的都跳过,没用是指该字符出现次数超过了目标串中出现的次数,并把它们出现次数都减1
                    while(start<i&&s[source[start]]>t[source[start]]){
                        s[source[start]]--;
                        start++;
                    }
                    //找到符合要求子串的首尾位置start 与 i, 这时候start指向该子串开头的字母,判断该子串长度
                    if(i-start<minLen){
                        minLen=i-start;
                        beg=start;
                        end=i;
                    }
                     s[source[++start]]--;
                     found--;//跳过无用的字符后,found减1,然后寻找更短的满足要求的字符串;
                }
            }
            /*如果beg值为-1,说明不存在这样的子串*/  
            if (beg == -1)  
                return "";  
            else  
                return source.substr(beg, end - beg + 1);  
        }
    };
    // 理解时,可以写一个字符串来模拟程序执行过程!

    题目有一些难度,参考http://blog.csdn.net/fly_yr/article/details/51134340

    应熟练此类题目。

  • 相关阅读:
    Ducking
    MINITAB(二)
    JFreechart
    linux命令0424
    JAVA哈哈镜
    HTML(四)
    The 3n+1 problem
    [转载]:【读书笔记】.NET本质论
    ER图基本步骤
    [从架构到设计]第一回:设计,应该多一点(转载)
  • 原文地址:https://www.cnblogs.com/Allen-rg/p/5795127.html
Copyright © 2020-2023  润新知