day 5 字符串专题(详细解读+代码举例)

1 字符串hash

思考一个问题:如何将一个二维整点P的坐标映射为一个整数,使得整点P可以由该整数唯一地代表。

假设一个点P的坐标为(x,y),那么可以令hash函数为H(P)=x*Range + y,这样对数据范围内的任意两个整点P1和P2,H(P1)都不会等于H(P2),就可以用H(P)唯一地代表该整点P,接着便可以通过整数hash的方法来进一步映射较小的范围。

字符串hash是指将一个字符串S映射为一个整数,使得该整数可以尽可能地唯一地代表字符串S。

例如假设字符串由大写字母A~Z构成,在这个基础上,令A=0,B=1…Z=25,这样就把26个大写字母对应到了二十六进制中,接着按照二十六进制转换为十进制的方法,就可以唯一地得到某个十进制数字。

int hashFunc(char S[],int len)
{
	int id=0;
	for(int i=0;i<len;i++)
	{
		id=id*26+(S[i]-'A';
	}
	return id;
}

显然,如果字符串S的长度比较长,那么转换得到的整数会很大。因此注意len的大小不能太大。

同理,如果又出现了小写字母a~z那么可以用五十二进制转换十进制,但这样导致得到的整数更大。

2 字符串hash进阶

对于上面的二十六进制转换为十进制的方法:

	id=id*26+(S[i]-'A');

在这个转换中,虽然字符串与整数是一一对应的,但是由于没有适当处理,可能产生极大的整数,因此为了应对这种情况,我们可以舍弃一些“唯一性”,将产生的结果对应一个整数mod取模,也就是使用下列函数:

id = (id*26+(S[i]-'A'))%mod

通过这种方式可以把字符串转换成范围内可以接受的整数。但这产生了重复问题,不过幸运的是在int范围内,如果进制数设置为一个10^7级别的素数(例如10000019),同时把mod设置为一个10的9次方级别的素数(如1000000007),那么冲突的概率会变得很小。

2 KMP算法

如果给出两个字符串text和pattern,需要判断字符串pattern是否是字符串text的子串,一般把字符串text称为文本串,而把字符串pattern称为模式串,例如给定文本串text=“caniwaitforyourheart”,那么模式串pattern=‘wait’是它子串,而pattern=‘sorry’就不是。

暴力破解当然简单,但是复杂度达到了O(mn)级别,是无法承受的。

下面利用KMP算法解决问题,复杂度仅仅为O(n+m)。

2.1 next数组

假设有一个字符串s,那么它以i号位作为结尾的子串就是s[0,1,…i]。对该子串来说,长度为k+1的前缀和后缀为s[0,1,…k],s[i-k…i],现在定义一个int型的数组next,其中next[i]表示使子串s[0,1,2…i]的前缀s[0,1,2,3…k]等于后缀s[i-k…i]的最大的k,如果找不到相等的前后缀,那么令next[i]=-1,。显然,next[i]就是所求最长相等前后缀中前缀最后一位的下标。
具体过程可以看下图:

在这里插入图片描述
举个例子,例如next[2]=0,此时字符串为abc,当k=0时,前缀是s[0]=a,后缀为s[2-0…2],所以后缀是s[2]=a,前后缀相等,得到k=0;

解决思路如下:

  1. 初始化数组next,令j=next[0]=-1;
  2. 让i在1~len-1范围遍历,对每个i,执行3和4
  3. 不断令j=next[j],知道j回退为-1,或者s[i]=s[j+1]成立
  4. 如果s[i]==s[j+1],则next[i]=j+1,否则next[i]=j;
void  getNext(char s[],int len)
{
	int j=-1;
	next[0]=-1;
	for(int i=1;i<len;i++)
	{
		while(j!=-1&&s[i]!=s[j+1]{
		j = next[j];
		}
		if(s[i]==s[j+1])
		{
			j++	;
		}
		next[i]=j;
	}
}

2.2 KMP算法

在此前的基础上,KMP就是依样画葫芦。

更定文本串text=‘abababaabc’,模式串pattern=‘ababaab’,如下图所示:
在这里插入图片描述
令i指向text的当前欲比较位,令j指向pattern中当前已被匹配的最后位,这样只要text[i]==pattern[j+1],成立就说嘛pattern[j+1]也被匹配成功,让i和j同时加一继续比较,知道j达到m-1说明pattern是text的子串。

接着继续匹配,此时i指向text[5],j指向pattern[4],表面pattern[0…4]已经匹配成功。但是显然text[5]跟pattern[4+1]匹配失败,难道我们需要从0开始继续比较么?当然不需要
在这里插入图片描述
为了不让j退回-1,应找到离当前j最近的j`,使得text[i]==pattern[j`+1]成立,并且pattern[0…j`]仍然与text的相应位置处于匹配状态。从这里可以看到,next数组的含义就是但j+1位匹配失败时,j应该回退到的位置。

因此KMP算法的思路就是:

  1. 初始化j=-1,表示pattern当前已被匹配的最后位
  2. 让i遍历文本text,对每个i,执行3,4来视图匹配text[i]和pattern[j+1]
  3. 不断令j=next[j],知道j回退为-1,或者是text[i]==pattern[j+1]成立
  4. 如果text[i]==pattern[j+1],则令j++,如果j达到m-1,说明pattern是text的子串,返回true
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用内容,你可以使用正则表达式来匹配日期时间字符串举例来说,如果你有一个字符串"2021-10-31 12:30:45",你可以使用正则表达式来提取其中的日期时间值。根据引用,你可以使用(?P...)这个正则表达式来提取。你可以将日期和时间分别提取出来,如下所示: ```python import re str = "2021-10-31 12:30:45" match = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})", str) year = match.group('year') month = match.group('month') day = match.group('day') hour = match.group('hour') minute = match.group('minute') second = match.group('second') print(year, month, day, hour, minute, second) ``` 这样,你就可以将日期时间字符串中的各个部分提取出来,分别赋值给对应的变量。在上面的例子中,输出将为:"2021 10 31 12 30 45"。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python正则表达式,获取字符串中的片段/正则表达式提取字符串](https://blog.csdn.net/qq_45281807/article/details/127768011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [python正则表达式如何匹配字符串](https://blog.csdn.net/weixin_36390615/article/details/113981523)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值