首页 > 其他分享 >来自 szc 的字符串和搜索的总结

来自 szc 的字符串和搜索的总结

时间:2023-11-17 10:15:45浏览次数:39  
标签:... int szc 搜索 哈希 字符串 inline 我们 回文

膜拜 szc 大佬。

原链接

题单+代码

哈希

普通哈希不讲了,讲讲树哈希。

对于判断一对同构树,要考虑相同结构的儿子在两类树的不同位置。

此时有两种方法,一种是正常的按序哈希,我们很好想到在哈希时对儿子节点的哈希值进行排序,规定一个顺序塞进去。

另一种方法则是不使用多项式哈希,对所有哈希值在不乘上模数的情况下进行求和,这样可以保证其哈希值是顺序无关的,而且好回溯。

为了防卡,此时我们就需要改变一下哈希函数的式子,如变成异或哈希。

P5043 树同构

哈希表

总有题目用的到哈希表的。

这里讲一下对于一个哈希表的冲突,我们通常使用散列表的方式(应该是叫这个),也叫拉链法。

就是把哈希值取个模,对于取模后的哈希值当做起点,造出一个连向该哈希值的边,对于查询时遍历该哈希值的模数后判断是否存在就行了。

这里是单哈希的板子(未实战慎复制)

struct HashTable{
	struct edge{
		struct node {
			ull w;
			int nxt,to;
		    node(int x=0,ull y=0,int z=0){
		    	to=x,w=y,nxt=z;
			}
		}e[N];
		int head[mod+1],tot;
		inline void add(int u,int v,ull w){
			e[++tot]=node(v,w,head[u]),head[u]=tot;
		}
		inline node&operator[](int x){return e[x];}
	}e;
    inline int get(ull key) { return (key%mod+mod)%mod; }
	int query(ull a){
		for(int i=e.head[get(a)];i;i=e[i].nxt)
			if(e[i].w==a) return e[i].to;
		return -1;
	}
	inline void insert(ull a,int b){
		int tmp=get(a);
		e.add(tmp,a,b);
	}
}fyn;

P5537 【XR-3】系统设计

KMP

KMP 常见于字符串匹配,简单复习一下。

定义 \(f_i\) 表示以 \(i\) 为结尾的字符串的后缀与原串能匹配的最长前缀。

对于新增节点 \(i\),我们已经知道了 \(i-1\) 的串长这样:

1234....f[i-1],x,...,(i-1)-f[i-1]+1,...,i-1,i

其中可以保证 $ i-1\sim (i-1)-f[i-1]+1$ 这一串字符是与 \(1\sim f[i-1]\) 相匹配的,则接下来对于新加进来的 \(i\) ,我们要将其与 \(x\) 进行配对。

若是相同的则 \(f[i]=f[i-1]+1\)。

若是不相同,我们就令失配指针跳到 \(f[i-1]\),即接下来串就变成了这个形式:

1234...f[f[i-1]],x,...f[i-1]-f[f[i-1]]+1,...,f[i-1],...,i

显然我们再对 \(x\) 进行以上的比较,直至失配指针变为 0 时,则代表 \(i\) 这个串找不到匹配的前缀。

kmp 例题就不放了,直接讲讲 kmp 套 dp 以及失配树。

P3426
P3502

以及 失配树

扩展KMP(Z函数)

考虑 \(z[i]\) 表示从 \(i\) 开始的字符串与原串的最长公共前缀。

考虑如何求得 \(z\)。

首先朴素算法,我们从 \(1\sim n\) 枚举每个点 i ,再暴力向后扫直到无法添加前缀,时间复杂度是 \(O(n^2)\) 的。

显然我们能优化的只有暴力向后扫的这个循环,考虑如何将 \(z[i]\) 从上一位转移过来。

我们记 \(i-1\) 得到的右端点最右的匹配串为 \(l,r\) ,则根据定义可知 \(S[l\sim r]\) 是 \(S\) 串的前缀。计算时保证 $l\le i $ 且初始 \(l=r=0\) 。

  • 若 \(i\le r\),则我们可以知道此时的 \(i\) 是处于该匹配串中的,而 \(r+1\) 是无法匹配的,因此我们可以得出 \(z[i]=min(z[i-l+1],r-i+1)\)

  • 否则我们以 \(i\) 为左端点再往右跑朴素算法。

这样子最终也是 \(O(n)\) 的。

CF432D

Manacher

首先考虑最朴素的回文串算法,暴力枚举中心点然后向左右拓展到无法添加为止,复杂度 \(O(n^2)\)。

首先回文串需要区分为奇数串和偶数串,而我们通过一个小技巧将其合并为一种情况。

我们首先往串中穿插 '#' ,构造出一个 \(2n+1\) 的字符串记为 \(S'\)。

对于在 \(S'\) 中的回文串其两端必然是 #,而奇数回文串必然以原字符串中的字符为中心,偶数串则是以我们穿插进去的 '#' 为中心。

考虑上一次计算后最大 \(r\) 值得子回文串为 \(l,r\)。

考虑新加入的 \(i\):

  • 若 \(i>r\) 则说明当前中心在回文串之外,我们使用朴素算法暴力向外拓展并更新 \(l,r\)。

  • 若 \(i\le r\),则说明 \(i\) 处在我们当前的回文串中,其必然有一个对称点 \(j\) ,且可以保证以 \(i\) 为中心至少存在一个长度与以 \(j\) 为中心的回文串相同的回文串。

显然此时我们还需要考虑若以 \(j\) 为中心的回文串超出边界时,我们并不能保证超过 \(r\) 的部分是关于 \(i\) 对称的,于是进行阻断,然后再继续往外跑朴素算法。

此后记得更新 \((l,r)\)

CF30E

Trie

Trie,字典树,顾名思义,字典树,一对多或许可以试试。

P4407 [JSOI2009] 电子字典

当然也可以用来求异或和最大。

P8511 [Ynoi Easy Round 2021] TEST

A*,IDA*

首先,了解一下这两个东西。

不要以为这是一个很高深的东西,实际上它是一个不那么高深的东西。

事实上就是一个加了优化的暴力。

A* 实际上就是加了估价函数的 bfs,最经典的就是求 K 短路。

对于每次拓展都贪心地选择我们从开始到当前点的花费加上我们预估接下来的花费的和最小的那个点,并进行拓展。

P2901 [USACO08MAR] Cow Jogging G

IDA* 实际上就是加了估价函数和迭代加深 (没有tim<=1e6) 的dfs,一般适用于拥有限制 (可以不可以总司令) 的题目。

然而这里的选择就有些不同,对于一个状态我们需要预估出该状态在最优情况下到达最终态的步数,及能走的最小步数,然后判断其加上当前深度是否超出迭代的最大深度,若超出则返回。

其实就是剪枝。

P2324 [SCOI2005] 骑士精神

以及 P3179 八数码

贴个八数码的 IDA*

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	auto _u=[](char x){return x>='0'&&x<='9';};
	for(;!_u(ch);ch=='-'&&(f=-1),ch=getchar());
	for(;_u(ch);x=(x<<1)+(x<<3)+(ch^48),ch=getchar());
	return x*f;
}
inline void write(int num,bool flag=0){
	static int st[39],tp=0;
	num<0&&(putchar('-'),num=-num);
	do st[++tp]=num%10;while(num/=10);
	while(tp) putchar(st[tp--]|48);
	putchar(flag?'\n':' ');
	return;
}
template<typename...Args>
inline void write(int t,Args...args){
	return write(t),write(args...);
}
short mp[3][3]={
	{1,2,3},
	{8,0,4},
	{7,6,5}
};
short a[3][3];
inline int check(){
	int cnt=0;
	for(int i=0;i<3;++i)
		for(int j=0;j<3;++j)
			cnt+=(a[i][j]!=mp[i][j]);
	return cnt;
}
int d[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
inline bool in(int x,int y){
	return x>=0&&x<3&&y>=0&&y<3;
}
bool dfs(int x,int y,int dep,int lst,int mxdep){
	if(dep==mxdep)return check()==0;
	for(int i=0,tx,ty;i<4;++i)
		if(in(tx=x+d[i][0],ty=y+d[i][1])&&lst+i!=3){
			swap(a[tx][ty],a[x][y]);
			if(check()+dep<=mxdep&&dfs(tx,ty,dep+1,i,mxdep)) return true;
			swap(a[tx][ty],a[x][y]);
		}
	return false;
}
inline void A_star(int x,int y){
	if(check()==0)puts("0");
	else for(int i=1;;++i) if(dfs(x,y,0,-1,i)) return write(i,true);
}
char s[10];
signed main(){
	scanf("%s",s);
	int x,y;
	for(int i=0;i<9;++i)
		if(!(a[i/3][i%3]=s[i]^48)) x=i/3,y=i%3;;
	A_star(x,y);
	return(0-0);
}

~

折半搜索,就是折一半搜索。

将原本的一组数据分组爆搜,再用一种时间复杂度较低的方法将各组数据合并为最终答案。

显然由此可得,我们不仅需要对可以暴力的数据范围敏感,还要对其倍数敏感。

P3067 [USACO12OPEN] Balanced Cow Subsets G

CF888E Maximum Subsequence

标签:...,int,szc,搜索,哈希,字符串,inline,我们,回文
From: https://www.cnblogs.com/djh0314/p/17838009.html

相关文章

  • Python模块的搜索路径
    在Python中,模块搜索路径是指解释器用来查找导入模块的位置列表。了解和掌握Python模块搜索路径对于正确导入模块和管理模块的位置至关重要。Python模块搜索路径的主要来源包括当前目录、Python标准库目录和用户自定义的目录。你可以通过sys模块中的sys.path来查看和修改模块搜索......
  • 151. 反转字符串中的单词
    2023-11-17思路:调用库函数+利用正则表达式利用栈双端队列头插链表利用数组总长度不知道按最大长度10^4利用list进阶:字符串可变时,Java不行,双指针,先整体反转,再逐个反转单词可以将空间复杂度降低 数组:classSolution{publicStringreverseWor......
  • 7-5 字符串排序
    目录目录目录题目代码思路第一次错误尝试错误原因正确代码运行结果关于二维数组的函数引用题目本题要求编写程序,读入5个字符串,按由小到大的顺序输出。输入格式:输入为由空格分隔的5个非空字符串,每个字符串不包括空格、制表符、换行符等空白字符,长度小于80。输出格式:按照以下......
  • 字符串哈希算法
    一、字符串哈希:将一串字符串映射成一个整数,并用它来代替字符串进行比较。这样俩个字符串的比较就变成俩个整数的比较,可以将时间复杂度减少至O(1)二、哈希函数:为了将字符串转化为整数,需要一个哈希函数hash,使得以下条件成立:如果字符串s==t那么hash(s)==hash(t)。一般情况下采......
  • 求删除k个字母后的最小字典序字符串
    对于一个字符串来说我们要找删除k个字母后的最小字典序字符串来说,我们肯定是从前往后来删除,如果遇见前一个字母比后一个字母(字典序)大,那就删除前一个。对于此来说我们用一个vector来维护,vector就是存的答案,如果vector的最后一个字母比枚举的字母大,那就删除最后一个。vector<c......
  • 找出一个字符串中出现次数最多的一个字符 找出重复签到的同学
    7-2找出一个字符串中出现次数最多的一个字符找出一个字符串中出现次数最多的一个字符。输入格式:给出一个字符串,字符串的长度不大于10^6,不区分大小写,字符串中可能包含'A'-'Z','a'-'z',''字符。输出格式:分别输出出现最多次数的字符(如果为字母,输出小写字母),出现的次数,用......
  • 344. 反转字符串
    2023-11-16344.反转字符串-力扣(LeetCode)思路:        //栈    //头插链表    //o1 双指针双指针:classSolution{publicvoidreverseString(char[]s){//栈//头插链表//o1双指针inti=0;......
  • 苏宁API:一键搜索,海量商品任你选!
    使用苏宁API按关键字搜索商品,可以在API的搜索参数中设置关键字。例如,在搜索商品时,可以在API的请求参数中设置q=关键字。例如,要搜索“鞋子”,可以将q设置为“鞋子”。另外,还可以设置其他的搜索参数,例如start_price和end_price可以设置价格范围,cat可以设置商品分类ID,sort可以设置排序......
  • [左神面试指南] 字符串[上]篇
    CD95判断两个字符串是否互为变形词/*模拟*/publicclassCD95_1{publicstaticbooleansolution(Strings1,Strings2){if(s1.length()!=s2.length())returnfalse;int[]temp=newint[256];for(charch:s1.toCharArray())......
  • 判断一个字符串中出现次数最多的字符,统计这个次数
    varstr="stiabsstringapbs";varobj={};for(vari=0;i<str.length;i++){varkey=str[i];if(!obj[key]){obj[key]=1;}else{obj[key]++;......