【刷题打卡】day2-字符串string

从现在开始每天至少刷一道题。
题库:lintcode

594. strStr II

题目链接
难度:hard
算法:Rabin–Karp

先普及两个知识点滚动哈希和Rabin–Karp算法

什么是滚动哈希?

首先了解一下通过哈希函数,将字符转化成数字,id(char) = char - ‘a’ + 1。 例如字符’c’可以转化成3。
滚动哈希指的是当前哈希值依赖上一个哈希值的结果作为输入。给定一个字符串s, i 为s的索引, hash(i) = (hash(i-1) * base + id(s[i]) ) % mod, 其中base, mod均为质数,且较大。核心思路就是将字符串通过哈希函数转换成数字。常常用来判断两个字符串是否相同。注意,哈希值加法和乘法运算后要对值取模,如果是减法,则要考虑负数的情况,加上mod后再取模, hash = (hash + mod) % mod.

题目1: 为什么id(char) = char - 'a' + 1,要+1
题目2:给定字符串s = “abcd”,mod = 10007, base = 31, 如何计算s的哈希值。
(答案见文末)

Rabin–Karp algorithm

根据wikepedia提供的解释,给定一个souce字符串 和pattern(target)字符串,找出source首次匹配pattern的索引。这里用到了滚动哈希。先计算pattern的哈希值,然后计算source中pattern length的子字符串的哈希值,如果两个哈希值相等,接着比较两个字符串的字符是否相等。

function RabinKarp(string s[1..n], string pattern[1..m])
    hpattern := hash(pattern[1..m]);
    for i from 1 to n-m+1
        hs := hash(s[i..i+m-1])
        if hs = hpattern
            if s[i..i+m-1] = pattern[1..m]

                return i
    return not found

解题思路
一看到这种字符串匹配的题目,就想想能不能套Rabin–Karp算法。

  1. 计算target的哈希值。假设target=“dec”, 哈希值就是(((d - a + 1)*base + (e-a + 1))*base + c - a + 1) % mod
  2. 遍历source,计算target length的子字符串的哈希值。方法就是加一个字符,减去头部的字符,维持一个固定长度的子字符串。比如,hash(“dec”) = hash(“adec”) - (‘a’ - ‘a’ + 1) * (base^targetLen)。左边最高位,右边最低位。

解法

	public class Solution {
    /*
     * @param source: A source string
     * @param target: A target string
     * @return: An integer as index
     */
    public int strStr2(String source, String target) {
        // write your code here
        if(target == null || source == null){
            return -1;
        }
        if(target.length() == 0){
            return 0;
        }
        if(source.length() == 0){
            return -1;
        }
        
        long base = 33;
        long mod = 10000007;
        int tlen = target.length();
        int slen = source.length();
        
        // compute hash value of target
        long targetHash = 0;
        for(int i=0;i<tlen;i++){
            targetHash = (targetHash * base + target.charAt(i) - 'a' + 1) % mod;
            
        }
        
        // compute base of target length
        long baseTmp = 1;
        for(int i=0;i<tlen;i++){
             baseTmp = baseTmp * base % mod;
        }

        
        int ans = -1;
        long sourceHash = 0;
        for(int i=0;i<slen;i++){
            sourceHash = (sourceHash * base + source.charAt(i) - 'a' + 1) % mod;
            
            if (i < tlen){
                continue;
            }
            sourceHash = (sourceHash - (source.charAt(i - tlen) - 'a' + 1) * baseTmp % mod) % mod;
            sourceHash = (sourceHash + mod) % mod;
            
            // System.out.printf("\nsourceHash=%d, targetHash=%d", sourceHash, targetHash);
            if (sourceHash == targetHash){
                ans = i - tlen + 1;
                break;
            }
        }
        
        return ans;

    }
}

841. String Repl

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值