Implement strStr -- LeetCode

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                原题链接:  http://oj.leetcode.com/problems/implement-strstr/  
这是算法中比较经典的问题,判断一个字符串是否是另一个字符串的子串。这个题目最经典的算法应该是KMP算法,不熟悉的朋友可以参见 Knuth–Morris–Pratt algorithm 。KMP算法是最优的线性算法,复杂度已经达到这个问题的下限。但是KMP算法比较复杂,很难在面试的短时间里面完整正确的实现。所以一般在面试中并不要求实现KMP算法。

下面我们先说说brute force的算法,假设原串的长度是n,匹配串的长度是m。思路很简单,就是对原串的每一个长度为m的字串都判断是否跟匹配串一致。总共有n-m+1个子串,所以算法时间复杂度为O((n-m+1)*m)=O(n*m),空间复杂度是O(1)。代码如下:

public int strStr(String haystack, String needle) {    if(haystack==null || needle == null || needle.length()==0)        return 0;    if(needle.length()>haystack.length())        return -1;    for(int i=0;i<=haystack.length()-needle.length();i++)    {        boolean successFlag = true;        for(int j=0;j<needle.length();j++)        {            if(haystack.charAt(i+j)!=needle.charAt(j))            {                successFlag = false;                break;            }        }        if(successFlag)            return i;    }    return -1;}

接下来介绍一种比较容易理解的线性算法,称为rolling hash,想具体了解的朋友可以参见 Rolling hash - Wikipedia 。基本思想是用一个hashcode来表示一个字符串,为了保证hash的唯一性,我们用比字符集大的素数为底,以这个素数的幂为基。举例来说,字符集是小写字母集,取素数29为底。比如字符串“abacd",转化为hashcode=1+2*29+1*29^2+3*29^3+4*29^4。然后是如何在前进一步的时候计算新的hashcode,比如匹配串是原串是”abacde“,匹配串长度为5,根据以上的方法计算”abacd“的hashcode=h,那么下一步”bacde“的hashcode=h/29+5*29^4。这是一个constant的操作,所以检测所有子串的时间复杂度只需要O(m+n-m)=O(n),也是一个线性算法。代码如下:

public String strStr(String haystack, String needle) {    if(haystack==null || needle==null) return null;    if(haystack.length()==0){        return needle.length()==0?"":null;    }    if(needle.length()==0) return haystack;    if(haystack.length()<needle.length()) return nullint base = 29long patternHash = 0;    long tempBase = 1;    for(int i=needle.length()-1; i>=0; i--){     patternHash += (int)needle.charAt(i)*tempBase;     tempBase *= base;    }    long hayHash = 0;    tempBase = 1;    for(int i=needle.length()-1; i>=0; i--){     hayHash += (int)haystack.charAt(i)*tempBase;     tempBase *= base;    }    tempBase /= base;    if(hayHash == patternHash){     return haystack;    }    for(int i=needle.length(); i<haystack.length(); i++){     hayHash = (hayHash - (int)haystack.charAt(i-needle.length())*tempBase)*base+(int)haystack.charAt(i);        if(hayHash == patternHash){      return haystack.substring(i-needle.length()+1);     }    }    return null;} 
比较细心的朋友可能看出来了,这个方法的hashcode比较容易越界,因为以素数为底的幂会很大,解决的办法可以用BigInteger,或者如同 Rabin–Karp algorithm - Wikipedia 一样对于hashcode进行取余,但是可能存在多个字符串映射到同一hashcode的问题,尽管是很少数的情况。

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值