Given an input string, reverse the string word by word.

本博客介绍了一个算法,用于反转给定字符串中单词的顺序并移除多余的空格,包括首尾及单词间的多余空格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

For example,
Given s = "the sky is blue",
return "blue is sky the".

click to show clarification.

Clarification:

  • What constitutes a word?
    A sequence of non-space characters constitutes a word.
  • Could the input string contain leading or trailing spaces?
    Yes. However, your reversed string should not contain leading or trailing spaces.
  • How about multiple spaces between two words?
    Reduce them to a single space in the reversed string.

题目解析:

(1)一开始首先将开头和结尾的空格去掉

(2)将剩余字符串逆转

(3)从头开始寻找将单词进行逆转,并将单词内的多余的空格去掉


#include <iostream>
#include <string>

using namespace std;

void reverseWords(string &s) {
	string::iterator it;

	int len = s.length();

	int begin = 0;
	int end = len-1;

	while(begin <= end && s[begin] == ' ')
	{
		it = s.begin() + begin;
		s.erase(it);
		end--;
	}
	if(s.length() == 0)
	{
		return;
	}

	while(end >=0 && s[end] == ' ')
	{
		it = s.begin() + end;
		s.erase(it);
		end--;
	}
	if(s.length() == 0)
	{
		return;
	}

	begin = 0;
	end = s.length()-1;

	int pBegin = begin;
	int pEnd = end;
	while(pBegin < pEnd)
	{
		char temp = s[pBegin];
		s[pBegin] = s[pEnd];
		s[pEnd] = temp;
		pBegin++;
		pEnd--;
	}

	int pSunEnd = begin;
	int pSunBegin = begin;
	while(pSunEnd <= end)
	{
		while(pSunEnd <= end && s[pSunEnd] != ' ')
			pSunEnd++;

		int tempEnd = pSunEnd-1;

		while(pSunBegin < tempEnd)
		{
			char c = s[pSunBegin];
			s[pSunBegin] = s[tempEnd];
			s[tempEnd] = c;

			pSunBegin++;
			tempEnd--;
		}

		pSunEnd++;
		while(pSunEnd <= end && s[pSunEnd] == ' ')
		{
			it = s.begin() + pSunEnd;
			s.erase(it);
			end--;
		}

		pSunBegin = pSunEnd;
	}
}

int main(void)
{
	string s("   the sky is   blue   ");

	cout << s.c_str() << endl;

	reverseWords(s);

	cout << s.c_str() << endl;
	system("pause");
	return 0;
}


<think>嗯,用户想找字符串中美丽的子串数量,美丽子串的定义是由非空字符串t和它的反转拼接成t + reverse(t) + t的形式。首先,我需要理解这个模式的结构。比如,如果t是"abc",那么反转就是"cba",美丽子串就是"abccbaabc"。那这样的子串需要满足前1/3是t,中间1/3是reverse(t),最后1/3又是t。对吧? 那问题转化为如何高效地在给定字符串中找到所有这样的子串。首先,得确定子串的长度必须是3k,其中k是t的长度。因为t的长度是k,反转后的部分也是k,再加上最后的t,总长3k。所以,首先需要遍历所有可能的子串长度,必须是3的倍数,比如3,6,9等。然后对于每个可能的长度,检查是否存在满足条件的子串。 接下来,如何判断一个子串是否符合模式呢?比如,对于长度为3k的子串,分成三个部分,每个部分k长。第一部分是t,第二部分应该是reverse(t),第三部分又应该是t。所以,要验证第二部分是否等于第一部分的逆序,同时第三部分等于第一部分。这一步可以用字符串切片和反转操作来实现。 但是直接暴力枚举所有可能的子串长度和起始位置,可能会很耗时,尤其是当字符串很长的时候。例如,对于长度为n的字符串,可能的子串长度有O(n)种,每个长度对应的子串数量也是O(n),所以总的时间复杂度可能是O(n^2),这在n较大时效率不高。可能需要寻找优化方法。 有没有办法预处理字符串,比如利用哈希或者前缀哈希来加速比较?或者利用回文相关的性质?比如,中间的reverse(t)实际上是t的反转,所以中间部分和第一部分是互为回文。不过第三部分又需要等于第一部分,所以整个结构是t + reverse(t) + t。这有点像回文结构,但又不完全是。 或者,可以预处理所有可能的k值,然后对于每个可能的k,遍历字符串中的每个起始位置i,检查是否存在满足条件的子串s[i:i+3k]。例如,k的取值范围从1到n//3,因为3k不能超过字符串长度n。对于每个k,i的取值范围从0到n-3k。然后对每个i和k,检查三个条件:s[i:i+k]是否等于s[i+2k:i+3k],以及s[i+k:i+2k]是否等于reverse(s[i:i+k])。这样,每个检查的时间复杂度是O(k),总的时间复杂度是O(n^2),对于较大的n来说可能不够高效。 那有没有办法优化这个检查过程?比如,使用滚动哈希或者Rabin-Karp算法来快速比较子串和反转后的子串。例如,预先计算字符串的前缀哈希和反转字符串的前缀哈希,这样比较两个子串是否相等可以在O(1)时间内完成。同样,反转后的部分可以通过反转字符串的哈希来处理。这可能会将时间复杂度降低到O(n^2),但系数更小,实际运行可能更快。 举个例子,假设原字符串是s,反转后的字符串是s_rev。对于子串s[i:i+k],它的反转应该是s_rev的某个子串。例如,s[i:i+k]的反转对应s_rev的[n-(i+k):n-i]部分。如果预处理原字符串和反转字符串的哈希,那么比较s[i:i+k]的反转是否等于s_rev的对应部分,可以转化为比较哈希值。或者,直接比较s[i+k:i+2k]是否等于s[i:i+k]的反转,可能需要逐个字符比较或者利用哈希。 另外,关于第三部分必须等于第一部分,也就是s[i+2k:i+3k]必须等于s[i:i+k]。同样,可以用哈希来快速比较。 假设已经预处理了原字符串的前缀哈希数组,那么对于任意子串的哈希值可以快速计算。这样,每个条件的检查都可以在O(1)时间内完成。因此,总的时间复杂度为O(n^2),但实际可能因为哈希的预处理而变得更快。 现在,具体步骤可能如下: 1. 遍历可能的k值,从1到最大可能的k,即n//3。 2. 对于每个k,遍历可能的起始位置i,从0到n-3k。 3. 对于每个i,检查三个条件: a. 第一部分s[i:i+k]是否等于第三部分s[i+2k:i+3k] b. 中间部分s[i+k:i+2k]是否等于第一部分的反转 4. 如果满足条件,则计数加一。 接下来,如何高效实现这些检查? 对于条件a,比较两个子串是否相等,可以用哈希预处理。例如,计算原字符串的滚动哈希,这样每个子串的哈希值可以快速得到。 对于条件b,需要比较中间部分是否等于第一部分的反转。这里,可以考虑将原字符串反转后的字符串的哈希也预处理,这样比较中间部分是否等于原字符串的某个子串的反转,可以转换为比较反转字符串对应位置的子串是否相等。例如,原字符串s的反转是s_rev,那么s[i:i+k]的反转是s_rev[ len(s) - (i+k) : len(s) -i ]。中间部分s[i+k:i+2k]是否等于反转后的s[i:i+k],即判断s[i+k:i+2k]是否等于s_rev[ len(s) - (i+k) : len(s) -i ]。因此,可以预处理s和s_rev的前缀哈希,这样比较这两个子串的哈希即可。 或者,更直接的方式是,对于每个i和k,直接比较中间部分是否等于第一部分的反转。例如,反转s[i:i+k]得到t_rev,然后比较中间部分是否等于t_rev。反转操作的时间是O(k),所以这一步的时间复杂度是O(k)。对于每个i和k来说,总的时间复杂度是O(k)*O(n^2) = O(n^3),这在n较大时不可行。因此,必须找到更高效的方式。 这时候,哈希的优势就显现了。如果预处理了原字符串和反转字符串的前缀哈希,那么可以快速获取任何子串的哈希值。例如,对于原字符串s,前缀哈希数组hash_s,每个位置i的哈希值表示s[0..i]的哈希。同样,反转后的字符串s_rev的前缀哈希数组hash_rev。那么,对于s的子串s[a..b],其哈希可以通过hash_s[b] - hash_s[a-1] * base^(b-a+1) mod mod_value。类似地,反转后的子串对应的哈希可以通过hash_rev的对应位置得到。 例如,s[i:i+k]的反转对应的哈希是s_rev的从位置n - (i+k)到n - i -1的长度为k的子串的哈希。这样,比较s[i+k:i+2k]的哈希是否等于s_rev的对应子串的哈希,即可判断条件b是否满足。 因此,预处理原字符串和反转字符串的滚动哈希,可以使得每个条件的判断在O(1)时间内完成,从而将总的时间复杂度降低到O(n^2)。 此外,还需要处理哈希冲突的问题,比如使用双重哈希(两个不同的基数和模数)来减少冲突的概率。 综上,算法的大致步骤是: 预处理步骤: 1. 计算原字符串s的前缀哈希数组(包括两个不同的哈希函数)。 2. 计算反转字符串s_rev的前缀哈希数组(同样使用两个哈希函数)。 3. 预处理幂数组,用于快速计算子串哈希。 遍历步骤: 对于每个可能的k(从1到n//3): 对于每个可能的i(从0到n-3k): 检查条件a:s[i..i+k-1] == s[i+2k..i+3k-1] → 使用哈希比较 检查条件b:s[i+k..i+2k-1] == reverse(s[i..i+k-1]) → 使用反转字符串的哈希比较 如果两个条件都满足,则计数加一。 这样,时间复杂度为O(n^2),但实际运行可能因为k的最大值较小而更快,例如当字符串长度为1e4时,k最大是约3333,但每个k对应的i的数量是1e4 -3k,所以总的循环次数大约是sum_{k=1}^{n/3} (n-3k+1) ≈ (n/3)*(n) )= n²/3 → 对于n=1e4来说,大约是3e8次,这可能会超时。因此,这种暴力方法可能无法处理较大的n。 这时候,需要寻找更优化的方法。例如,是否存在数学规律或结构,可以快速判断符合条件的k和i? 例如,观察美丽子串的结构:t + reverse(t) + t。假设t的长度是k,那么整个子串的结构是t的反转被夹在两个t之间。这可能意味着t本身必须满足某些回文性质吗?比如,t是否是回文?不一定,因为中间的reverse(t)可能与t的结构无关。 或者,考虑将整个子串视为三个部分,其中中间部分是第一部分的反转,第三部分是第一部分。例如,整个子串可以表示为ABC,其中A = t, B = reverse(t),C = t。那么整个子串的长度是3k。要满足这个结构,A必须等于C,并且B等于A的反转。 有没有办法通过寻找重复的模式来优化?例如,寻找所有可能的t,使得在字符串中存在三个位置,分别对应这三个部分。但具体如何操作还不清楚。 或者,可以分步骤处理。首先,找出所有可能的t的位置,然后检查是否存在对应的B和C部分。例如,对于每个可能的t(即每个可能的子串A),检查是否存在后续的reverse(A)和A的再次出现。 但这种方法同样可能效率不高,因为需要枚举所有可能的t。 另一个思路是,将问题转化为寻找满足A + B + A的结构,其中B是A的反转。因此,整个子串的结构是A + reverse(A) + A。那么,这样的子串的长度为3k,其中k是A的长度。 现在,问题转化为在字符串中找到所有这样的子串,其中中间部分为前面部分的反转,而最后的部分等于前面部分。 例如,对于字符串中的某个位置i和长度k,检查是否存在这样的结构: s[i..i+k-1] = A s[i+k..i+2k-1] = reverse(A) s[i+2k..i+3k-1] = A 如果能快速找到这样的三元组,就能统计美丽子串的数量。 为了高效查找,可以预处理每个可能的k值,并对于每个可能的i,快速判断这三个条件是否满足。 回到之前的哈希预处理方法,这可能依然是目前可行的方案,但需要处理大字符串时的性能问题。 例如,当字符串长度为1e4时,总共有大约1e4 * 1e4 /3次循环,这大约是3e8次,这在普通计算机上可能需要较长时间(假设每次循环需要几个纳秒,那么3e8次大约是0.3秒左右,可能勉强可行)。但如果是更大的字符串,比如1e5长度,这显然不可行。所以需要更优化的方法。 有没有可能通过观察模式的结构,找到某些数学上的规律,从而减少需要检查的k和i的数量? 例如,考虑美丽子串的结构,A + reverse(A) + A。假设存在这样的子串,那么整个子串的前k字符和后k字符是相同的,即A。中间k字符是reverse(A)。那么,整个子串的前k和后k字符必须相同,中间的k字符是前k的反转。 因此,可以首先找出所有满足s[i..i+3k-1]的前k和后k字符相同的子串,然后在这些子串中检查中间k字符是否等于前k的反转。 这可能减少需要检查的条件数量,因为先筛选出前k和后k相同的子串,然后再检查中间部分。但如何高效找出前k和后k相同的子串? 例如,对于每个可能的k,遍历i,检查s[i..i+k-1]是否等于s[i+2k..i+3k-1]。如果相等,再检查中间部分是否是前者的反转。这可能减少一部分的检查次数,因为先过滤掉不符合条件的i和k的组合。 但这一步骤的时间复杂度仍然是O(n^2),只是实际循环次数可能减少。比如,对于每个k,先遍历i,找出满足条件a的i,然后在这些i中检查条件b。这可能在条件a的检查通过率较低的情况下节省时间。 此外,有没有其他特征?比如,整个美丽子串的前k和后k字符相同,中间k字符是它们的反转。这可能使得整个子串具有某些回文特性。例如,整个子串的前半部分(前1.5k字符)是否是回文?或者整个子串的某些部分是否形成回文? 或者,可以将整个子串视为A + reverse(A) + A的结构,其中A的长度为k。这可能意味着整个子串中,A的出现位置和反转后的A的位置存在某种对称性。例如,中间的reverse(A)必须是原A的反转,而最后又出现A。这种情况下,可能无法直接利用回文的性质,但可以结合哈希预处理。 综上,目前最直接的解决方案可能还是基于哈希的暴力枚举,尽管时间复杂度是O(n²),但对于中等长度的字符串是可行的。如果用户需要处理非常大的字符串,可能需要更高效的算法,但目前可能没有明显的优化思路。 接下来,考虑如何具体实现这个算法。例如,在Python中,如何实现滚动哈希? 滚动哈希通常选择一个基数和模数,例如,基数可以是10^9+7和另一个大质数,模数可以是10^18+3。然后预处理前缀哈希数组和幂数组。对于每个子串的哈希,可以通过前缀哈希的差值乘以基数的幂次来得到。 例如,原字符串s的前缀哈希数组hash_s,其中hash_s[i]表示前i个字符的哈希值。对于子串s[a..b],其哈希值为 (hash_s[b] - hash_s[a] * pow(base, b-a, mod)) % mod。同样,反转后的字符串s_rev的前缀哈希数组处理方式类似。 在Python中,可以预先计算这些数组。然后,在检查两个子串是否相等时,比较它们的哈希值是否相同。但需要注意哈希冲突的可能性,所以最好使用双哈希,即同时计算两个不同的基数和模数的哈希,只有当两个哈希值都相等时才认为子串相等。 另外,Python中的字符串反转可以通过切片操作s[::-1]来实现,但生成反转字符串可能会消耗O(n)的空间。对于哈希预处理来说,反转字符串的预处理是必须的。 现在,具体实现步骤: 1. 预处理原字符串s的前缀哈希数组,使用两个不同的哈希参数(base1, mod1)和(base2, mod2)。 2. 预处理反转后的字符串s_rev的前缀哈希数组,同样使用上述两个哈希参数。 3. 预处理幂数组,用于快速计算不同长度的子串哈希。 4. 遍历所有可能的k,从1到max_k(即n//3)。 5. 对于每个k,遍历所有可能的i,从0到n-3k。 6. 对于每个i,检查: a. 子串s[i:i+k]是否等于子串s[i+2k:i+3k](使用双哈希比较)。 b. 子串s[i+k:i+2k]是否等于s_rev中对应位置的子串,即s_rev的从n - (i+k)到n -i的位置,也就是s_rev[ (n -i -k) : (n -i) ],这相当于原字符串s的s[i:i+k]的反转。 7. 如果两个条件都满足,则美丽子串计数加一。 需要注意的是,反转字符串的处理。例如,原字符串s的长度为n,那么s_rev的第p个字符对应原字符串的第n-1 -p个字符。因此,在反转字符串s_rev中,子串s_rev[a:a+k]对应原字符串s的子串s[n -a -k : n -a ]的反转。 所以,当需要比较s[i+k:i+2k]是否等于reverse(s[i:i+k])时,可以转换为比较该子串是否等于s_rev的对应位置子串。例如,reverse(s[i:i+k])等于s_rev[ (n - i -k) : (n -i) ]。因此,在反转字符串s_rev中,对应的子串是s_rev[ (n -i -k) : (n -i) ],其长度为k。因此,比较s[i+k:i+2k]和s_rev的该子串是否相等即可。 所以,在哈希预处理中,原字符串和反转字符串的前缀哈希都需要处理。例如,对于原字符串s的哈希,可以处理其前缀哈希,而反转字符串s_rev的前缀哈希则用于快速比较反转后的子串。 现在,编写代码的大致结构: 预处理部分: 计算s的哈希数组hash1和hash2,以及反转字符串的rev_hash1和rev_hash2。 计算幂数组pow1和pow2,用于快速计算子串哈希。 比较函数: def get_hash(h, p, a, l, k): # 返回从a开始长度为l的子串的哈希值,使用预计算的哈希数组h和幂数组p,基数k return (h[a + l] - h[a] * p[l]) % mod 当比较两个子串是否相等时,比较它们的两个哈希值是否都相等。 现在,具体到Python代码的实现,例如: 假设选择的base1=911382629,mod1=10^18+3,base2=3571428571,mod2=10^18+7。 预处理函数: def precompute_hashes(s, base, mod): n = len(s) hash_array = [0]*(n+1) pow_array = [1]*(n+1) for i in range(n): hash_array[i+1] = (hash_array[i] * base + ord(s[i])) % mod pow_array[i+1] = (pow_array[i] * base) % mod return hash_array, pow_array 然后,对于原字符串s和反转后的字符串rev_s,分别计算两个哈希参数的哈希数组。 例如: s = input_string rev_s = s[::-1] hash1_s, pow1_s = precompute_hashes(s, base1, mod1) hash2_s, pow2_s = precompute_hashes(s, base2, mod2) hash1_rev, pow1_rev = precompute_hashes(rev_s, base1, mod1) hash2_rev, pow2_rev = precompute_hashes(rev_s, base2, mod2) 然后,定义获取子串哈希的函数: def get_sub_hash(h_array, p_array, start, length, mod): if start + length > len(h_array)-1: return None # 越界 return (h_array[start + length] - h_array[start] * p_array[length]) % mod 在比较两个子串是否相等时,需要比较两个哈希参数的结果是否都相等。 例如,比较s的子串a到a+k和s的子串b到b+k: hash_a_1 = get_sub_hash(hash1_s, pow1_s, a, k, mod1) hash_a_2 = get_sub_hash(hash2_s, pow2_s, a, k, mod2) hash_b_1 = get_sub_hash(hash1_s, pow1_s, b, k, mod1) hash_b_2 = get_sub_hash(hash2_s, pow2_s, b, k, mod2) 如果 hash_a_1 == hash_b_1 且 hash_a_2 == hash_b_2,则认为两个子串相等。 同样,比较中间部分s[i+k:i+2k]与反转后的s[i:i+k]: 原字符串s的i到i+k的反转对应于反转字符串rev_s中的位置n - (i +k)到n -i的位置。因为rev_s的每个字符是原s的反转,所以rev_s的第p位对应原s的n-1-p位。因此,原s的子串s[i..i+k-1]的反转等于rev_s的从位置n - (i +k)到n -i的位置的子串。例如,i=0,k=3,原子串是s[0:3],反转是rev_s[ n-3 : n ],即原s的末尾三个字符的反转。 因此,在反转字符串rev_s中,对应的子串位置是 start_rev = n - (i +k),长度为k。所以,反转后的子串在rev_s中的起始位置是n -i -k,结束位置是n -i。 因此,比较s[i+k : i+2k]和rev_s[n -i -k : n -i ]是否相等。这可以通过哈希比较: hash_mid_1 = get_sub_hash(hash1_s, pow1_s, i+k, k, mod1) hash_mid_2 = get_sub_hash(hash2_s, pow2_s, i+k, k, mod2) hash_rev_1 = get_sub_hash(hash1_rev, pow1_rev, n -i -k, k, mod1) hash_rev_2 = get_sub_hash(hash2_rev, pow2_rev, n -i -k, k, mod2) 如果 hash_mid_1 == hash_rev_1 且 hash_mid_2 == hash_rev_2,则中间部分等于反转后的A。 这样,就能快速比较条件a和条件b。 综上,整个算法的Python实现可能如下: 实现步骤: 1. 预处理原字符串和反转字符串的双哈希。 2. 遍历所有可能的k,从1到max_k。 3. 对每个k,遍历i从0到n-3k。 4. 对每个i,检查条件a和条件b。 5. 统计符合条件的子串数目。 可能的优化点: - 预先计算max_k = len(s) // 3,避免不必要的循环。 - 使用双哈希减少冲突概率。 - 预处理幂数组,避免重复计算。 现在,编写代码的草稿: 假设输入字符串为s: n = len(s) max_k = n // 3 count = 0 # 预处理原字符串和反转字符串的双哈希 rev_s = s[::-1] # 哈希参数 base1 = 911382629 mod1 = 10**18 + 3 base2 = 3571428571 mod2 = 10**18 + 7 # 预处理原字符串的哈希 hash1_s, pow1_s = precompute_hashes(s, base1, mod1) hash2_s, pow2_s = precompute_hashes(s, base2, mod2) # 预处理反转字符串的哈希 hash1_rev, pow1_rev = precompute_hashes(rev_s, base1, mod1) hash2_rev, pow2_rev = precompute_hashes(rev_s, base2, mod2) for k in range(1, max_k + 1): for i in range(0, n - 3*k +1): # 检查条件a:s[i:i+k] == s[i+2k:i+3k] a_start = i a_end = a_start + k c_start = i + 2*k c_end = c_start + k # 获取哈希值 hash_a1 = get_sub_hash(hash1_s, pow1_s, a_start, k, mod1) hash_a2 = get_sub_hash(hash2_s, pow2_s, a_start, k, mod2) hash_c1 = get_sub_hash(hash1_s, pow1_s, c_start, k, mod1) hash_c2 = get_sub_hash(hash2_s, pow2_s, c_start, k, mod2) if (hash_a1 != hash_c1) or (hash_a2 != hash_c2): continue # 条件a不满足,跳过 # 检查条件b:s[i+k:i+2k] == reverse(s[i:i+k]) # reverse(s[i:i+k])对应rev_s中的位置:n - i -k到n -i mid_start = i + k mid_end = mid_start + k rev_start = n - i -k rev_end = rev_start + k hash_mid1 = get_sub_hash(hash1_s, pow1_s, mid_start, k, mod1) hash_mid2 = get_sub_hash(hash2_s, pow2_s, mid_start, k, mod2) hash_rev1 = get_sub_hash(hash1_rev, pow1_rev, rev_start, k, mod1) hash_rev2 = get_sub_hash(hash2_rev, pow2_rev, rev_start, k, mod2) if (hash_mid1 == hash_rev1) and (hash_mid2 == hash_rev2): count +=1 print(count) 但需要注意,在反转字符串rev_s中的子串rev_s[rev_start : rev_start +k]对应的是原字符串s的子串s[i:i+k]的反转。所以在比较时,中间部分s[i+k:i+2k]的哈希必须等于rev_s的对应子串的哈希。 此外,处理反转字符串的哈希时,precompute_hashes函数必须正确处理rev_s的字符顺序。例如,rev_s是原字符串的反转,所以每个字符的位置是原字符串的倒序。 这样,该代码应该能够正确计算出美丽子串的数量。但需要注意哈希计算时的边界条件,例如子串的起始和结束位置是否越界。 可能的测试案例: 例如,输入字符串为"ababa",那么美丽子串有哪些? 假设k=1: i=0,子串长度3:检查i=0,k=1: 子串为s[0:1] = 'a',中间部分s[1:2] = 'b',第三部分s[2:3] = 'a'。条件a:a和第三部分的a相等。条件b:中间部分是否是reverse(a)=a?这里中间部分是b,所以不满足。所以不计数。 i=0,k=2可能不行,因为总长度3k=6,但原字符串长度5,不够。 另一个测试案例:假设字符串是"aaa",k=1: i=0时,子串长度为3。三个部分都是a。中间部分应该是reverse(a)=a,满足条件。所以这是一个美丽子串。计数为1。 另一个案例:字符串是"abbaabbaabba"。可能需要找出满足条件的结构。 综上,该算法能够正确处理这些情况。 用户的问题还要求生成相关问题。根据问题内容,可能的关联问题包括如何优化该算法的时间复杂度,或者如何处理更复杂的情况,或者该问题与其他字符串问题的关联。</think>### 分步解答 要计算字符串中美丽子串的数量(美丽子串定义为$t + reverse(t) + t$形式),可采用以下步骤: 1. **预处理双哈希** 使用滚动哈希技术预处理原字符串和反转字符串的哈希值,通过两个不同的哈希基数和模数降低碰撞概率: $$hash(s[0..n]) = (s[0] \cdot base^{n} + s[1] \cdot base^{n-1} + ... + s[n]) \mod mod$$ 2. **遍历可能的子串长度** 美丽子串长度必须为$3k$,其中$k$为$t$的长度。遍历所有可能的$k$($1 \leq k \leq \lfloor n/3 \rfloor$)。 3. **验证子串结构** 对每个起始位置$i$和长度$k$,验证: - 条件1:$s[i..i+k] = s[i+2k..i+3k]$(首尾部分相同) - 条件2:$s[i+k..i+2k] = reverse(s[i..i+k])$(中间部分为反转) 4. **哈希快速比较** 通过预处理的哈希值,将字符串比较优化为$O(1)$时间操作,确保整体时间复杂度为$O(n^2)$。 ```python def count_beautiful_substrings(s: str) -> int: n = len(s) if n < 3: return 0 # 双哈希参数 base1, mod1 = 911382629, 10**18 + 3 base2, mod2 = 3571428571, 10**18 + 7 # 预处理原字符串和反转字符串的哈希 rev_s = s[::-1] def precompute(s, base, mod): hash_arr = [0] * (len(s)+1) pow_arr = [1] * (len(s)+1) for i in range(len(s)): hash_arr[i+1] = (hash_arr[i] * base + ord(s[i])) % mod pow_arr[i+1] = (pow_arr[i] * base) % mod return hash_arr, pow_arr hash1_s, pow1_s = precompute(s, base1, mod1) hash2_s, pow2_s = precompute(s, base2, mod2) hash1_rev, pow1_rev = precompute(rev_s, base1, mod1) hash2_rev, pow2_rev = precompute(rev_s, base2, mod2) count = 0 max_k = n // 3 for k in range(1, max_k + 1): for i in range(n - 3*k + 1): # 检查条件1:首尾相同 a_start, c_start = i, i + 2*k h_a1 = (hash1_s[a_start + k] - hash1_s[a_start] * pow1_s[k]) % mod1 h_a2 = (hash2_s[a_start + k] - hash2_s[a_start] * pow2_s[k]) % mod2 h_c1 = (hash1_s[c_start + k] - hash1_s[c_start] * pow1_s[k]) % mod1 h_c2 = (hash2_s[c_start + k] - hash2_s[c_start] * pow2_s[k]) % mod2 if (h_a1 != h_c1) or (h_a2 != h_c2): continue # 检查条件2:中间是反转 mid_start = i + k rev_pos = n - i - k # 反转后的起始位置 h_mid1 = (hash1_s[mid_start + k] - hash1_s[mid_start] * pow1_s[k]) % mod1 h_mid2 = (hash2_s[mid_start + k] - hash2_s[mid_start] * pow2_s[k]) % mod2 h_rev1 = (hash1_rev[rev_pos + k] - hash1_rev[rev_pos] * pow1_rev[k]) % mod1 h_rev2 = (hash2_rev[rev_pos + k] - hash2_rev[rev_pos] * pow2_rev[k]) % mod2 if h_mid1 == h_rev1 and h_mid2 == h_rev2: count += 1 return count ``` ### 示例分析 输入字符串`"ababa"`时: - 候选$k=1$,遍历所有可能的$i$,发现`i=1`时子串`"bab"`满足$t="b"$,结构为$b + a + b$,不满足中间为反转; - $k=1$时无解,最终结果根据实际匹配情况确定。 ### 算法优化 - **哈希加速**:通过双哈希降低碰撞概率至可接受范围; - **剪枝策略**:当条件1不满足时直接跳过条件2的检查; - **时间复杂度**:$O(n^2)$,适用于中等长度字符串($n \leq 10^4$)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值