LeetCode-实现Strstr

题解

双指针法

  这道题是字符串匹配问题,第一反应当然是KMP算法和BF算法,虽然前两天刚学了KMP,自己动手写还是不会写next数组。按自己思路写了双指针算法,虽然提交通过,但是代码质量极差可以称为垃圾代码…,运行时间1960ms…

#include "iostream"
#include "string"
using namespace std;
class Solution {
public:
	int strStr(string haystack, string needle) {
	    if(needle.length()==0||needle==haystack)return 0;
	    if(needle.length()>haystack.length())return -1;
	    int i;
	    for(i=0;i<haystack.length();i++)
	    {
	        //从匹配的首位开始后序步骤
	        if(haystack[i]==needle[0])
	        {
	            //如果needle只有一位,那么直接返回i
	            if(needle.length()==1) return i;
	            else
	            {
	                //开始从haystack串i的下一位开始于needle的	第二位开始比较
	                for(int j=1,k=i+1;j<needle.length()	&&k<haystack.length(); )
	                {
	                    //如果后序一位继续相等,就把j,k向后移,结束标志是needle串遍历到尾部
	                    if (needle[j]==haystack[k])
	                    {
	                        j++;
	                        k++;
	                        if(j==needle.length())return i;
	                    }
	                    //如果后序任意有一位不相等,就跳出这个循环,继续寻找和needle串首位相等的元素位
	                    else
	                    {
	                        break;
	                    }  
	                }
	            }
	        }
	    }
	    //若haystack遍历结束 仍没有返回true,则不存在子串
	    return -1;
	}
};

库函数法

  偷个懒,调函数。

#include "iostream"
#include "string"
using namespace std;
class Solution {
public:
	int strStr(string haystack, 	string needle) {
	    if(needle.empty())	return 0;
	    else
	    {
	        int 	pos=haystack.find	(needle);
	        return pos;
	    }
	    return -1;
	}
};   

BF算法

  暴力解法,但比我的代码高效的多,匹配成功时,各自+1,比较下一位。匹配失败下标就要回溯,对于needle串,要回溯到0的位置,对于Haystack串,则返回到i-j+1的位置。

#include "iostream"
#include "string"
using namespace std;
class Solution {
public:
	int strStr(string haystack, string needle) {
        //加几个很好想到的特殊情况,加快判断
        if(needle.empty() || needle==haystack )	return 0;
        if(needle.length()>haystack.length())	return -1;

        int i=0,j=0;
        while(needle[i]!='\0' 	&& haystack[j] !='\0')
        {
            if(needle[i]	==haystack[j])
            {
                i++;
                j++;
            }
            else  //回溯
            {   
                //haystack从上次匹配的下一位开始 needle从头开始
	            j=j-i+1;
	            i=0;
	        }
	    }
	    if(needle[i]=='\0')	return j-i;
	    else return -1;
	}
};

KMP算法

class Solution {
public:
	vector<int> getnext(string str)
	    {
	        int len=str.size();
	        vector<int> next;
	        next.push_back(-1);//next数组初值为-1
	        int j=0,k=-1;
	        while(j<len-1)
	        {
	            if(k==-1||str[j]==str[k])//str[j]后缀 str[k]前缀
	            {
	                j++;
	                k++;
	                	next.push_back(k);
	            }
	            else
	            {
	                k=next[k];
	            }
	        }
	        return next;
	    }
	int strStr(string haystack, string needle) {
	    if(needle.empty())
	        return 0;
    
	    int i=0;//源串
	    int j=0;//子串
	    int len1=haystack.size();
	    int len2=needle.size();
	    vector<int> next;
	    next=getnext(needle);
	    while((i<len1)&&(j<len2))
	    {
	        if((j==-1)||(haystack[i]==needle[j]))
	        {
	            i++;
	            j++;
	        }
	        else
	        {
	            j=next[j];//获取下一次匹配的位置
	        }
	    }
	    if(j==len2)
	        return i-j;
	    
	    return -1;
	}
};

KMP算法next数组优化

  next数组可以进行优化,当字符失配时,回到相同字符无意义,应继续递归。

 vector<int> getnext(string str)
    {
        int len=str.size();
        vector<int> next;
        next.push_back(-1);//next数组初值为-1
        int j=0,k=-1;
        while(j<len-1)
        {
            if(k==-1||str[j]==str[k])//str[j]后缀 str[k]前缀
            {
                j++;
                k++;
                if(str[j]!=str[k])
                    next.push_back(k);
                else
                    next.push_back(next[k]);
            }
            else
            {
                k=next[k];
            }
        }
        return next;

  以下几种算法来自

https://leetcode-cn.com/problems/implement-strstr/solution/c5chong-jie-fa-ku-han-shu-bfkmpbmsunday-by-2227/

的总结,还没有很理解,先收藏进来。

BM算法

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;//移动距离
	}

	int strStr(string haystack, string needle) {
    
    	int i=0;
    	int j=0;
    	int tlen=needle.size();
    	int slen=haystack.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;
	}
};

Sunday

class Solution {
public:
	int strStr(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;//当超过源串长度时 
	}
};
发布了36 篇原创文章 · 获赞 0 · 访问量 597

猜你喜欢

转载自blog.csdn.net/weixin_43199933/article/details/105001568