c# - 使用 C# 实现 Rabin-Karp 算法以在 LeetCode 28 "implement strStr()"中搜索字符串的问题

标签 c# algorithm

我实现了这个算法来解决 Leetcode 的 #28 问题“implemment strStr()”。
问题描述:
实现 strStr(), 返回 needle 在 haystack 中第一次出现的索引,如果 needle 不是 haystack 的一部分,则返回 -1。

我的代码是基于http://www.geeksforgeeks.org/searching-for-patterns-set-3-rabin-karp-algorithm/实现的的教程。

我发现使用不同的质数来缩小哈希值时,函数可能会出错。
这是我的代码:

    public class Solution {
    public int StrStr(string haystack, string needle) {
        int len = needle.Length;
        //2 special case
        if (haystack.Length < len) return -1;
        if (needle == "") return 0;

        //base prime number used for rabin-karp's hash function
        int basement = 101;
        //prime number used to scale down the hash value
        int prime = 101;
        //the factor used to multiply with the character to be removed from the hash
        int factor = (int)(Math.Pow(basement, needle.Length - 1)) % prime;

        //get ascii value of the needle and the initial window
        int needleHash = 0;
        int windowHash = 0;
        byte[] needleBytes = Encoding.ASCII.GetBytes(needle);
        byte[] windowBytes = Encoding.ASCII.GetBytes(haystack.Substring(0, len));

        //generate hash value for both
        for (int i = 0; i < needle.Length; i++)
        {
            needleHash = (needleHash * basement + needleBytes[i]) % prime;
            windowHash = (windowHash * basement + windowBytes[i]) % prime;
        }

        //loop to find match
        bool findMatch = true;
        for (int i = 0; i < haystack.Length - len + 1; i++){
            //if hash value matches, incase the hash value are not uniq, iterate through needle and window
            if(needleHash == windowHash){
                findMatch = true;
                for (int j = 0; j < len; j++)
                {
                    if (needle[j] != haystack[i + j])
                    {
                        findMatch = false;
                        break;
                    }
                }
                if (findMatch == true) return i;
            }
            //move the sliding window and find the hash value for new window
            if (i < haystack.Length - len){
                byte removeByte = Encoding.ASCII.GetBytes(haystack.Substring(i, 1))[0];
                byte addByte = Encoding.ASCII.GetBytes(haystack.Substring(i + len, 1))[0];
                //function of rolling hash
                windowHash = ((windowHash - removeByte * factor) * basement + addByte) % prime;
                //ensure the window hash to be positive
                if(windowHash < 0) windowHash += prime;
            }
        }
        return -1;
    }
}  

将“prime”设置为“101”,此代码通过了所有测试。但是,如果我将它更改为其他质数,无论大小(例如:17、31、103),它总是在测试“68/72”时失败

haystack = "baabbaaaaaaabbaaaaabbabbababaabbabbbbab babbbbbbbababaabbbbbaaabbbbaabababababbaabbbbaaabbaaba bbbaabaabbabbaaaabababaaabbabbababbbaaabbbbabbbbbabbabbaabbbaa";
针 = "bbaaaababa";

因此我确实相信我的代码存在我无法检测到的大问题。为什么会这样?

最佳答案

您的代码有两个问题:

  1. basement 应根据您用作引用的网站上的算法设置为 256。该值是输入字母表中的字符数。
  2. 您对factor 的计算不正确;在计算余数之前,您要转换为 intMath.Pow 运算产生的 double 值大于 Int32.MaxValue。当您转换为 int before 模运算时,您将截断该值。您需要使用 double 值执行模运算,然后然后转换为 int。该行应如下所示:

    int factor = (int)((Math.Pow(basement, needle.Length - 1)) % prime);

我使用这些修改和给出的示例测试了您的代码,它适用于 17、31、101 和 103 的素数。

关于c# - 使用 C# 实现 Rabin-Karp 算法以在 LeetCode 28 "implement strStr()"中搜索字符串的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32576677/

相关文章:

c# - 在单元测试中为 ApiController 设置用户属性

c# - 具有通用属性的类必须是通用的?

python - 将数字列表划分为2个相等总和列表的算法

algorithm - 证明度数 = 2 的连通图具有哈密顿环

c# - 如何使用 CanExecuteChanged 事件管理器

c# - Index was outside the bounds of the array 异常

c# - Xamarin.Forms FindByName() 总是返回 null

arrays - 找出两个排序数组的最大总和

python - 检测并提取字符串列表中不断变化的数字

algorithm - 找到图像中最大的凸黑色区域