首页 > 其他分享 >简单字符串 学习笔记

简单字符串 学习笔记

时间:2024-02-29 09:25:09浏览次数:22  
标签:int void tr pos 笔记 学习 异或 字符串

目录

  1. 字符串哈希

  2. 字典树

  3. 字典树的倒序建树

  4. KMP

正文

1. 字符串哈希

1.1 基础

可以在数字和字符串之间快速转化。

考虑一个哈希函数:\(f(s)=(\sum\limits_{i=0}^{n}s_i\times base^{n-i+1})\)。

容易发现这些值是唯一的。但是取模时需要选一个较大模数,减少冲突概率。

const ll mod=1e10+19,base=100073;
string s;
ll gethash(string s) {
    ll ans=0;
    for(int i=0; i<=(int)s.size(); i++) ans=(ans*base+(int)s[i])%mod;
    return ans;
}

1.2 字符串哈希做 KMP

显然可以预处理出 \(base^i\) 及其逆元,然后指针移动的时候改哈希值判断即可。

2. 字典树

2.1 定义

设 \(tr_{i,j}\) 表示第 \(i\) 个节点经过 \(j\) 指向的位置。

2.2 插入和删除

插入时,对于每个点,如果未访问则新开一个点,如果已经访问过则往下跳。
同时,维护 ans 数组表示这个点经过的次数。有时候需要维护 vis 数组表示这个位置是不是一个字符串的末尾。

void insert(string s) {
    int x=0;
    for(int i=0; i<(int)s.size(); i++) {
        if(!t[x][get(s[i])]) t[x][get(s[i])]=++cnt;
        x=t[x][get(s[i])],ans[x]++;
    }
    vis[x]=1;
}

删除同理。

查询时直接往下跳,如果 t 值未访问则说明未出现过。否则继续往下跳,跳到末尾返回 vis 值即可。

bool query(string s) {
    int x=0;
    for(int i=0; i<(int)s.size(); i++) {
        if(!t[x][get(s[i])]) return 0;
        x=t[x][get(s[i])];
    }
    return vis[x];
}

关于字典树模板,则返回 ans 值。

2.3 01-trie

插入、删除、查询同理。

重点介绍处理异或问题。

例如多次询问一个数和集合中那个数异或值最大。

尽量从高向低走和这个数相反的位置,计算答案。

3. 字典树的倒序建树

by xjd。

pushup

从低位往高位建树可以维护不同的信息,比如支持查询全局异或和,全局加一。

维护两个数组 \(v,w\),分别表示子树异或和、子树叶节点个数的奇偶性。类似线段树,有一个用子节点更新当前节点的函数:

void pushup(int pos){
  w[pos]=v[pos]=0;
  if(tr[pos][0])w[pos]^=w[tr[pos][0]],v[pos]^=v[tr[pos][0]]<<1;
  if(tr[pos][1])w[pos]^=w[tr[pos][1]],v[pos]^=(v[tr[pos][1]]<<1)|w[tr[pos][1]];
}

对于 \(w\),直接将子树相加即可。当前节点的 \(v\) 异或上左右子树的 \(v\)。由于从低位往高位建树,左右儿子的 \(v\) 要左移一位。当前节点往右儿子的边会产生 \(0\) 或 \(1\) 的贡献,应单独算。

那么全局异或和就是根节点的 \(v\)。

查询、删除

由于 pushup 的存在,递归会好写一点。

void insert(int a,int &pos,int d){
  if(!pos)pos=++cnt;
  if(d>maxd)w[pos]^=1;
  else insert(a>>1,tr[pos][a&1],d+1),pushup(pos);
}
void erase(int a,int pos,int d){
  if(d>maxd)w[pos]^=1;
  else erase(a>>1,tr[pos][a&1],d+1),pushup(pos);
}

全局加一

对一个数加一,二进制上会把最低位的零与更低位翻转。放到字典树上就是交换左右儿子然后沿着走零的边。

void add(int pos){
  swap(tr[pos][0],tr[pos][1]);
  if(tr[pos][0])add(tr[pos][0]);
  pushup(pos);
}

4. KMP

对于字符串 \(s\),定义 \(\bold{Border}(s)\) 为对于 \(i \in \left [1, |s|\right)\),满足 \(pre_i=suf_i\) 的字符串 \(pre_i\) 的集合。\(\bold{Border}(s)\) 中的每个元素都称之为字符串 \(s\) 的 \(\operatorname{border}\)。也就是字符串的最长子串,满足它既是真前缀也是真后缀。

对于一个字符串,定义其前缀函数是一个数组 \(nxt\),\(nxt_i\) 是前缀 \(pre_i\) 的最长 \(\operatorname{border}\) 的长度。

考虑怎么快速算 \(nxt\)。

  int j=0;
  for(int i=2; i<=m; i++) {
    while(j&&t[i]!=t[j+1]) //如果跳回第一个就不用跳了
      j=nxt[j];//匹配
    if(t[j+1]==t[i]) j++;
    nxt[i]=j;//i+1失配后应该如何跳
  }

可以理解为模式串当前位置和自己前面段匹配。

最后直接在文本串上跳即可。

void kmp() {
    for(int i=1,j=0; i<=n; i++) {
        for(; j>0&&t[j+1]!=s[i]; j=nxt[j]);
        if(t[j+1]==s[i]) j++;
        if(j==m) cout<<i-m+1<<'\n';
    }
}

复杂度分析:考虑 \(j\) 每次往前匹配,但最多加一,所以是 \(O(n+m)\)。

标签:int,void,tr,pos,笔记,学习,异或,字符串
From: https://www.cnblogs.com/lgh-blog/p/18042655

相关文章

  • RASP部署笔记
    一.什么是RASPRASP全称是RuntimeApplicationSelfProtect,其基本思路是将防护代码注入到应用运行的关键函数中,实现应用运行态的入侵检测与防护。例如,为了检测任意文件上传攻击,我们可以将防护代码注入到文件写入基础函数中。在java中,这个函数是FileOutputStream的构造函数。我们通......
  • 基于MATLAB深度学习工具箱的CNN卷积神经网络训练和测试
    一、理论基础    为了尽可能详细地介绍基于MATLAB深度学习工具箱的CNN卷积神经网络训练和测试,本文将按照以下内容进行说明:CNN卷积神经网络的基本原理深度学习工具箱的基本介绍CNN卷积神经网络训练的步骤和方法CNN卷积神经网络的优缺点1.CNN卷积神经网络的基本原理 ......
  • MatLab深度学习
    1.深度学习介绍公司官网有个很好的深度学习(DeepLearning)介绍文档。他们在视频中对深度学习的解释就是:DeepLearningisamachinelearningtechniquethatlearningfeaturesandtasksdirectlyfromdata.深度学习是机器学习的一种,从数据中直接学习特性和功能。深度学习......
  • 《系统科学方法概论》第三章读书笔记
    读完《系统科学方法概论》的第三章后,我对系统科学方法有了更深入的理解和认识。这一章介绍了系统分析方法,让我明白了如何从整体的角度去理解和研究复杂的系统。系统分析强调对系统的各个组成部分进行全面的考察,并考虑它们之间的相互关系。这种方法帮助我更好地把握系统的本质和特......
  • 《系统科学方法概论》第四章读书笔记
    读完《系统科学方法概论》的第四章后,我对系统分析方法有了更深入的理解和认识。这一章详细介绍了系统分析的概念、步骤和方法,让我明白了系统分析在解决复杂问题中的重要性。通过对系统的各个组成部分进行分解和分析,我们可以更好地理解系统的整体行为和特性。我认识到系统分析需......
  • 《系统科学方法概论》第五章读书笔记
    读完《系统科学方法概论》的第五章后,我对系统分析方法有了更深入的理解和认识。这一章详细介绍了系统分析的概念、步骤和方法,让我明白了系统分析在解决复杂问题中的重要性。通过对系统的各个组成部分进行分解和研究,我们可以更好地理解系统的整体行为和特性。我认识到系统分析需......
  • Linux学习-day6
    问题回顾ssh登录Linux服务器默认有7个终端,按Ctrl+alt+F1~F7可以进行切换;SSH远程登录服务器Windows下命令写法:[email protected](端口不写默认是22)Linux下命令写法:[email protected]关于登录与退出登录登录系统[email protected]退出登录exit......
  • 《程序是怎样跑起来的》第九章读书笔记
    在阅读第九章后,我对文件和文件系统有了更全面的认识。这一章详细介绍了文件的概念、文件的存储与管理方式,以及文件系统的工作原理。我了解到文件是数据的长期存储形式,它们在计算机系统中起着至关重要的作用。文件系统提供了一种组织和管理文件的方式,使得我们能够方便地存储、读取......
  • 《程序是怎样跑起来的》第十章读书笔记
    读完第十章后,我对文件和输入输出有了更全面的认识。这一章详细介绍了文件的概念、文件的操作以及输入输出的处理方式。我了解到文件作为数据的持久存储介质,在程序中起着重要的作用。通过文件,我们可以将数据长期保存下来,并在需要时进行读取和处理。文件的管理和操作需要注意文件的......
  • C++ 多线程笔记1 线程的创建
    C++多线程笔记1线程的创建里面代码会用到的头文件#include<iostream>#include<string>#include<memory>#include<thread>#include<vector>#include<stdlib.h>#include<cmath>#include<chrono>#include<ctime>入门例子vo......