[字符串模式匹配]leetcode28:实现strStr() (easy) [六种解法]

题目:
[字符串模式匹配]leetcode28:实现strStr() (easy) [六种解法]_第1张图片
题解:

class Solution {
public:
    //解法1:库函数
    int strStr_1(string haystack, string needle) {
        return haystack.find(needle);
    }
    
    //解法2:暴力破解,时间复杂度为O((h-n)*n)
    int strStr_2(string haystack,string needle)
    {
        if(needle.empty())return -1;
        int h=haystack.size(),n=needle.size();
        //haystack的下标范围为[0,h-n]表示haystack的前h-n+1的字符都至少比较1次,当i取值为h-n时表示haystack中还有n的字符需与needle比较
        for(int i=0;i<=h-n;++i)
        {
            int j=0;//每次循环重置j为0
            for(;j<n;++j)
                if(haystack[i+j]!=needle[j])
                    break;
            if(j==n)return i;//找到匹配
        }
        return -1;//未找到匹配
    }
    
    //解法3:暴力破解显式回退,时间复杂度为O((h-n)*n)
    int strStr_3(string haystack,string needle)
    {
        int i=0,h=haystack.size();
        int j=0,n=needle.size();
        for(;i<h&&j<n;++i)
        {
            if(haystack[i]==needle[j])++j;
            else {i-=j;j=0;}
        }
        //找到匹配,此时的i指向子串在文本串中尾元素之后的下标,需减去子串的长度得到第一个匹配成功的下标
        if(j==n)return i-n;
        //匹配不成功
        else return -1;
    }    
};

解法4:KMP算法,时间复杂度为O(h+n)

class Solution {
public:
    //解法4:KMP算法,时间复杂度为O(h+n)
    vector<int> get_next(string &str)//获取next数组
    {
        vector<int> next;
        next.push_back(-1);//next的初始值为-1
        int j=0,k=-1;
        while(j<str.size()-1)
        {
            //next的前两个元素为-1,0
            if(k==-1||str[j]==str[k]){j++;k++;next.push_back(k);}
            else k=next[k];
        }
        return next;
    }
    //KMP算法
    int strStr_4(string haystack,string needle)
    {
        if(needle.empty())return 0;
        int i=0,h=haystack.size();
        int j=0,n=needle.size();
        vector<int> next=get_next(needle);
        while(i<h&&j<n)
        {
            if(j==-1||haystack[i]==needle[j]){++i;++j;}
            else j=next[j];//获取下一次匹配的位置
        }
        return j==n?i-j:-1;
    }
};

解法5:BM算法,时间复杂度最坏为O(h*n),最佳为O(h)

class Solution {
public:
    void get_bmB(string& T,vector<int>& bmB)//坏字符
    {
        int tlen=T.size();
        for(int i=0;i<256;i++)//不匹配直接移动子串
        {
            bmB.push_back(tlen);
        }
        for(int i=0;i<tlen-1;i++)//靠右原则
        {
            bmB[T[i]]=tlen-i-1;
        }
    }
    
    void get_suff(string& T,vector<int>& suff)
    {
        int tlen=T.size();
        int k;
        for(int i=tlen-2;i>=0;i--)
        {
            k=i;
            while(k>=0&&T[k]==T[tlen-1-i+k])
                k--;
            suff[i]=i-k;
        }
    }
    
    void get_bmG(string& T,vector<int>& bmG)//好后缀
    {
        int i,j;
        int tlen=T.size();
        vector<int> suff(tlen+1,0);
        get_suff(T,suff);//suff存储子串的最长匹配长度
        //初始化 当没有好后缀也没有公共前缀时
        for(i=0;i<tlen;i++)
            bmG[i]=tlen;
        //没有好后缀 有公共前缀 调用suff 但是要右移一位 类似KMP里的next数组
         for(i=tlen-1;i>=0;i--)
            if(suff[i]==i+1)
                for(j=0;j<tlen-1;j++)
                    if(bmG[j]==tlen)//保证每个位置不会重复修改
                        bmG[j]=tlen-1-i;
        //有好后缀 有公共前缀
           for(i=0;i<tlen-1;i++)
            bmG[tlen-1-suff[i]]=tlen-1-i;//移动距离
    }
     //解法5:BM算法,时间复杂度最坏为O(h*n),最佳为O(h)
    int strStr_5(string haystack, string needle) {       
        int i=0,slen=haystack.size();
        int j=0,tlen=needle.size();
        
        vector<int> bmG(tlen,0);
        vector<int> bmB;
        get_bmB(needle,bmB);
        get_bmG(needle,bmG);
        while(i<=slen-tlen)
        {
            for(j=tlen-1;j>-1&&haystack[i+j]==needle[j];j--);
            if(j==(-1))
                return i;
            i+=max(bmG[j],bmB[haystack[i+j]]-(tlen-1-j));
        }
        return -1;
    }
};

解法6:sunday算法,最差时间复杂度为O(h*n),最佳为O(h)

class Solution {
public:
    int strStr_6(string haystack, string needle) {
        if(needle.empty())
            return 0;
        int slen=haystack.size();
        int tlen=needle.size();
        int i=0,j=0;//i指向源串首位 j指向子串首位
        int k;
        int m=tlen;//第一次匹配时 源串中参与匹配的元素的下一位
        
        for(;i<slen;)
        {
            if(haystack[i]!=needle[j])
            {
                for(k=tlen-1;k>=0;k--)//遍历查找此时子串与源串[i+tlen+1]相等的最右位置
                 {
                    if(needle[k]==haystack[m])
                        break;
                }
                i=m-k;//i为下一次匹配源串开始首位 Sunday算法核心:最大限度跳过相同元素
                j=0;//j依然为子串首位
                m=i+tlen;//m为下一次参与匹配的源串最后一位元素的下一位
                if(m>slen)//当下一次参与匹配的源串字数的最后一位的下一位超过源串长度时
                    return -1;
            }
            else
            {
                if(j==tlen-1)//若j为子串末位 匹配成功 返回源串此时匹配首位
                    return i-j;
                i++;
                j++;
            }
        }
        return -1;//当超过源串长度时 
    }
};

你可能感兴趣的:(leetcode刷题)