C - AB Substrings

本文探讨了一种算法,旨在通过重新排列并连接一组字符串,以最大化特定子串“AB”的出现次数。该方法首先分析每个字符串的首尾字符,然后根据特定规则进行连接,以确保目标子串的最大化出现。

Problem Statement
Snuke has N strings. The i-th string is si.

Let us concatenate these strings into one string after arranging them in some order. Find the maximum possible number of occurrences of AB in the resulting string.

Constraints1≤N≤1042≤|si|≤10si consists of uppercase English letters.
Input
Input is given from Standard Input in the following format:

N s1。。。sN

Output
Print the answer.

Sample Input 1
Copy
3
ABCA
XBAZ
BAD
Sample Output 1
Copy
2
For example, if we concatenate ABCA, BAD and XBAZ in this order, the resulting string ABCABADXBAZ has two occurrences of AB.

Sample Input 2
Copy
9
BEWPVCRWH
ZZNQYIJX
BAVREA
PA
HJMYITEOX
BCJHMRMNK
BP
QVFABZ
PRGKSPUNA
Sample Output 2
Copy
4
Sample Input 3
Copy
7
RABYBBE
JOZ
BMHQUVA
BPA
ISU
MCMABAOBHZ
SZMEHMA
Sample Output 3
Copy
4

这个思路叭,可以说是最蠢的了,就是把字符串按规则连起来,暴力
容易超时
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<string>
#define ll long long
#define dd double
using namespace std;
 
int main(){
	string s[10005];
	string st="";
	ll a[10005][3]={0};
	memset(a,0,sizeof(a));
	ll n;cin>>n;
	for(ll i=0;i<n;i++){
		cin>>s[i];
		if(s[i][0]=='B'){
			a[i][0]++;
		}
		if(s[i][s[i].size()-1]=='A'){
			a[i][1]++;
		}
	}
	ll flag=0;
	for(ll i=0;i<n;i++){
		if(a[i][0]==0&&a[i][1]!=0){
			flag=1;
			st+=s[i];
			a[i][2]=-1;
			break;
		}
	}
	ll q=0;
	if(flag==1){
		for(ll i=0;i<n;i++){
			if(a[i][2]==-1){
				continue;
			}
			else{
				if(a[i][0]!=0&&a[i][1]!=0){
					st+=s[i];
					a[i][2]=-1;
				}
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]==-1){
				continue;
			}
			else{
				if(a[i][0]!=0){
					st+=s[i];
					a[i][2]=-1;
					break;
				}
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]==-1){
				continue;
			}
			else{
				if(q%2==0){
					if(a[i][1]!=0){
						st+=s[i];
						a[i][2]=-1;
						i=-1;
						q++;
					}
				}
				else{
					if(a[i][0]!=0){
						st+=s[i];
						a[i][2]=-1;
						i=-1;
						q++;
					}
				}
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]!=-1){
				st+=s[i];
				a[i][2]=-1;
			}
		}
	}
	if(flag==0){
		for(ll i=0;i<n;i++){
			if(a[i][1]!=0&&a[i][2]!=-1){
				st+=s[i];
				a[i][2]=-1;
				break;
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]==-1){
				continue;
			}
			else{
				if(a[i][0]!=0&&a[i][1]!=0){
					st+=s[i];
					a[i][2]=-1;
				}
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]==-1){
				continue;
			}
			else{
				if(a[i][0]!=0){
					st+=s[i];
					a[i][2]=-1;
				}
			}
		}
		for(ll i=0;i<n;i++){
			if(a[i][2]!=-1){
				st+=s[i];
				a[i][2]=-1;
			}
		}
	}
	ll count = 0;
	for(ll i=0;i<st.size()-1;i++){
		if(st[i]=='A'&&st[i+1]=='B'){
			count++;
		}
	}
	cout<<count<<endl;
} 
<think>好的,我现在需要详细解释最长公共子串(Longest Common Substring)的定义和实现方法。首先,得明确最长公共子串和最长公共子序列(Longest Common Subsequence)的区别,避免混淆。最长公共子串要求字符连续,而子序列不需要。比如,"abcde"和"abfce"的公共子串是"ab"或"ce",而最长公共子序列可能是"abce"。 接下来,用户需要了解具体的实现方法。根据提供的引用资料,动态规划是常用的方法。我需要先解释动态规划的基本思路,然后逐步构建解决方案。比如,动态规划表的结构,如何填充表格,以及如何通过表格回溯找到最长子串。 然后,具体步骤可能需要详细展开。例如,创建一个二维数组dp,其中dp[i][j]表示以字符串a的第i个字符和字符串b的第j个字符结尾的最长公共子串的长度。当a[i-1]等于b[j-1]时,dp[i][j] = dp[i-1][j-1] + 1,否则为0。同时,记录最大值和结束位置,以便最后提取子串。 需要检查引用的不同语言的实现,确保算法的一致性。比如引用3和4中的Java和C++代码都使用了类似的动态规划方法,二维数组的处理方式也相似。此外,引用5中提到优化思路,即不需要存储整个二维数组,只需要前一行的数据即可,这样可以优化空间复杂度,但可能用户的问题暂时不需要深入优化,所以可能放在后面作为补充。 另外,用户可能需要时间复杂度分析。动态规划方法的时间复杂度是O(m*n),其中m和n是两个字符串的长度。空间复杂度如果使用二维数组的话也是O(m*n),但可以优化到O(n)或O(m)如果只保留一行或一列的数据。 最后,要生成相关问题,参考用户之前的例子,比如如何优化空间复杂度,不同实现方式的比较,或者应用场景等。这些问题应该与最长公共子串相关,并且能够帮助用户进一步学习。 需要注意用户提供的引用中有一些代码示例,比如JavaScript和Objective-C的实现,可能需要提及不同语言实现的差异,但用户主要问题可能更关注算法本身,所以重点放在算法步骤而不是具体代码。 总结回答结构:先定义,然后动态规划步骤,时间复杂度分析,代码示例(选择Python作为例子,因为用户提供的示例中有Python代码),最后应用场景和相关问题。</think>### 最长公共子串(Longest Common Substring)定义与实现 #### 定义 最长公共子串是指两个或多个字符串中**连续相同**的最长子序列。例如,字符串 $s_1 = \text{"abcde"}$ 和 $s_2 = \text{"abfce"}$ 的最长公共子串是 $\text{"ab"}$ 或 $\text{"ce"}$(长度均为2)。与最长公共子序列(LCS)不同,公共子串要求字符必须连续[^3][^5]。 --- #### 动态规划实现方法 ##### 核心思想 通过构建二维数组 $dp[i][j]$,记录以字符串 $a$ 的第 $i$ 个字符和字符串 $b$ 的第 $j$ 个字符结尾的最长公共子串长度。递推公式为: $$ dp[i][j] = \begin{cases} dp[i-1][j-1] + 1 & \text{if } a[i-1] = b[j-1] \\ 0 & \text{otherwise} \end{cases} $$ 同时,记录全局最大值 $max\_length$ 及其结束位置 $index$,以便提取子串[^3][^4][^5]。 ##### 步骤详解 1. **初始化二维数组**:第一行和第一列设为0,简化边界条件。 2. **填充数组**:遍历两字符串的每个字符,若字符相等,则当前值等于左上角值加1。 3. **更新最大值**:每次计算 $dp[i][j]$ 后,更新全局最大值和索引。 4. **提取结果**:根据记录的索引和长度,从原字符串中截取子串。 ##### 时间复杂度与空间复杂度 - **时间复杂度**:$O(m \times n)$($m,n$ 为字符串长度) - **空间复杂度**:$O(m \times n)$,可优化至 $O(\min(m,n))$[^5]。 --- #### Python实现示例 ```python def longest_common_substring(a, b): m, n = len(a), len(b) dp = [[0] * (n+1) for _ in range(m+1)] max_length = 0 end_index = 0 for i in range(1, m+1): for j in range(1, n+1): if a[i-1] == b[j-1]: dp[i][j] = dp[i-1][j-1] + 1 if dp[i][j] > max_length: max_length = dp[i][j] end_index = i else: dp[i][j] = 0 return a[end_index - max_length : end_index] if max_length > 0 else "" ``` --- #### 应用场景 1. **DNA序列比对**:寻找生物序列中的相似片段。 2. **文本相似度分析**:检测抄袭或重复内容。 3. **版本控制系统**:识别代码修改的公共部分[^1][^2][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值