首页 > 编程语言 >字符串哈希算法

字符串哈希算法

时间:2023-06-13 15:35:11浏览次数:38  
标签:... hash limits sum mid 算法 哈希 字符串

问题描述

考虑 1044. 最长重复子串 (Hard),本题思路并不难,可以使用二分答案来解决,假设答案为 mid,那么长度大于 mid 的子串在 s 中只会出现一次,否则至少出现两次。

因此只需要考虑子串在 s 中的出现次数即可,比较直接的想法是使用 key 为 stringunordered_map,然而 unoredere_map 自带的哈希函数,其时间复杂度和空间复杂度都很高,为 $O(len)$,因此,需要一个简单一点的哈希函数。

字符串哈希

参照宫水三叶大佬的 字符串哈希

我们需要使用一个比字符串 s 略长的哈希数组 vector<int> h(s.size() + 10),以及次方数组 vector<int> p(s.size() + 10)。 对长度为 len 的数组,只需要利用前缀和思想 h[i + len] - h[i] * p[len] 即可在 $O(1)$ 时间内计算出哈希值。

其中 p[0] = 1h[i] = h[i - 1] * P + s[i - 1]p[i] = p[i - 1] * P

$P$ 可以依次取 $131,\ 13131,\ 1313131$ 等,出现哈希碰撞就考虑取更大的质数。

其所使用的哈希函数计算方法本质为:$hash(s) = \sum\limits_{i = 1}^{l} s[i - 1] * P^{l - i}$(其中 $l$ 是字符串 $s$ 的长度)。

对这个前缀和计算公式作一个简单证明: $hash(s[1...r]) = \sum\limits_{i = 1}^{r}s[i - 1] * P^{r - i},hash(s[1...l]) = \sum\limits_{i = 1}^{l}s[i - 1]*P^{l - i}$

$hash(s[1...r]) -P^{r - l} * hash(s[1...l]) = \sum\limits_{i = 1}^{l}s[i - 1]P^{r-l+l-i} +\sum\limits_{i=l+1}^{r}s[i - 1] P^{r-i}-P^{r-l}*\sum\limits_{i = 1}^{l}s[i - 1]P^{l - i} = \sum\limits_{i=l+1}^{r}s[i - 1] P^{r-i}$

而 $hash(s[l + 1...r]) = \sum\limits_{i = l}^{r}s[i - 1] * P^{r - i}$

即 $hash(s[1...r]) - hash(s[1...l]) * P^{r - l} = hash(s[l + 1...r])$

代码

class Solution {
  public:
    string check(int mid, string &s, vector<uint64_t> &h, vector<uint64_t> &p) {
        unordered_set<uint64_t> substrs;
        for (int i = 0; i + mid <= s.size(); ++i) {
            int j = i + mid;
            long hash = h[j] - h[i] * p[j - i];
            if (substrs.find(hash) != substrs.end()) {
                return s.substr(i, mid);
            }
            substrs.insert(hash);
        }
        return "";
    }
    string longestDupSubstring(string s) {
        // 二分查找答案,左边界为0,右边界为 s.size(),左闭右开
        unordered_map<string, int> substr;
        int left = 0, right = s.size();
        string ans;
        int P = 1313131, n = s.size();
        vector<uint64_t> h(n + 10);
        vector<uint64_t> p(n + 10);
        p[0] = 1;
        for (int i = 0; i < n; ++i) {
            p[i + 1] = p[i] * P;
            h[i + 1] = h[i] * P + s[i];
        }
        while (left < right) {
            int mid = left + (right - left) / 2;
            string tmp_res = check(mid, s, h, p);
            if (!tmp_res.empty()) {
                left = mid + 1;
            } else {
                right = mid;
            }
            ans = ans.size() < tmp_res.size() ? tmp_res : ans;
        }
        return ans;
    }
};

标签:...,hash,limits,sum,mid,算法,哈希,字符串
From: https://www.cnblogs.com/zwyyy456/p/17477656.html

相关文章

  • 快速选择算法
    问题描述给定一个长度为$n$的数组,如何在$O(n)$的时间复杂度内找到第$k$大的数。思路朴素的想法是先排序,然后直接找到第$k$个元素,时间复杂度为$O(n\logn)$。我们可以利用快速排序的思想来解决这个问题,考虑快速排序的划分过程,在快速排序的“划分”结束后,数组$A_p\cdotsA_r$被......
  • kmp算法
    问题描述kmp算法解决的是字符串匹配问题,即:字符串P是否是字符串S的子串?如果是,它出现在s的哪些位置?这里我们称S为主串,P为模式串。思路首先是暴力匹配算法(Brute-Force算法),代码如下:voidBruteForce(strings,stringp){intlen_s=s.size(),len_p=p.size();fo......
  • LRU 算法与 LFU 算法
    算法介绍LRULRU全称是LeastRecentlyUsed,即最近最久未使用算法。LRU根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高,它是页面置换算法的一种,也常用于缓存设计。LFULFU全称是LeastFrequentlyUsed,根据频率来选择要......
  • 代码随想录算法训练营第六天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数
    454.四数相加II1,难点:1,多个数组之间,会有重复出现的数组,如果单用multiset也是会出错的2,如果用mutliset,在使用distance找出来equal_range的值的时候,也是会出现奇怪的错误的2,正确思路1,把重复出现的节点,次数存放到map种,然后进行遍历3,代码:1intfourSumCount(v......
  • Python如何把字符串中形如'\uXXXX'的Unicode字符转换为原始字符
    jsonpickle保存的文本有形如"\u6211\u7684"的字符,看起来很不方便,怎么转换为原始字符呢?参考如下代码:importjsonpickle#定义一个包含Unicode编码字符的字符串text="我的名字是\u674e\u5b87\u5b87"#将字符串保存为JSON格式json_string=jsonpickle.encode(text)......
  • 湖边的烦恼-算法训练题
    湖边的烦恼-算法训练题-递归问题描述每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育......
  • ChatGPT之问艺道:如何借助神级算法Prompt,让你轻松get到更高质量答案?
    摘要:本文由葡萄城技术团队编写,文章的内容借鉴于IbrahimJohn的《TheArtofAskingChatGPT》(向ChatGPT提问的艺术)。前言当今,ChatGPT赢得越来越多人的青睐,人们通过它输入问题并获取答案。但除了简单的一问一答以外,ChatGPT还有许多隐藏的提问方式,是否想要一探究竟?今天,我们为您......
  • 代码随想录算法训练营第24天 | ● 理论基础 ● 77. 组合 - 第7章 回溯算法part01
     第七章 回溯算法part01今日内容: ●  理论基础 ●  77. 组合    详细布置   理论基础  其实在讲解二叉树的时候,就给大家介绍过回溯,这次正式开启回溯算法,大家可以先看视频,对回溯算法有一个整体的了解。 题目链接/文章讲解:https://programmercar......
  • 代码随想录算法训练营第25天 | ● 216.组合总和III ● 17.电话号码的字母组合 - 第7章
     第七章 回溯算法part02 今日内容:  ●  216.组合总和III●  17.电话号码的字母组合  详细布置   216.组合总和III  如果把 组合问题理解了,本题就容易一些了。  题目链接/文章讲解:https://programmercarl.com/0216.%E7%BB%84%E5%90%88%E6%80%B......
  • python 中格式化字符串
     001、format>>>"{0}love{1}.{2}".format("I","FishC","com")##位置参数'IloveFishC.com'>>>"{a}love{b}.{c}".format(a="I",b="FishC"......