子字符串问题

链接:https://www.patest.cn/contests/gplt/L1-006

L1-006. 连续因子

时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

一个正整数N的因子中可能存在若干连续的数字。例如630可以分解为3*5*6*7,其中5、6、7就是3个连续的数字。给定任一正整数N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

输入格式:

输入在一行中给出一个正整数N(1<N<231)。

输出格式:

首先在第1行输出最长连续因子的个数;然后在第2行中按“因子1*因子2*……*因子k”的格式输出最小的连续因子序列,其中因子按递增顺序输出,1不算在内。

输入样例:
630
输出样例:
3
5*6*7

题解:要理解子字符串的一些规律:子字符串是从一个字符串中取出任意大小的字符,模拟这个过程:该字符串的每个字符为子字符串的首字符,然后从该首字符开始向后添加字符,当遇到满足的条件时,进行相应的更新操作。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<climits>
#include<cmath>

using namespace std;

int main()
{
	int n;
	while(scanf("%d",&n) != EOF)
	{
		int k = 0,count = 0;
		for(int i = 2; i < sqrt(n); i++)
		{
			long long  ans = 1;//注意相乘可能会溢出! 
			for(int j = i; ans*j <= n; j++)
			{
				ans = ans*j;
				if(n%ans == 0)
				{
					if(count < j-i+1)
					{
						k = i;
						count = j-i+1;
					}
				}
			}
		}
		if(count == 0)
			printf("1\n%d\n",n);
		else
		{
			printf("%d\n",count);
			count = count+k;
			for(int i = k; i < count-1; i++)
			{
				printf("%d*",i);
			}
			printf("%d\n",count-1);	
		}
	 } 
 return 0;
}


链接:https://www.nowcoder.com/acm/contest/91/L

来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

给一个数组 a,长度为 n,若某个子序列中的和为 K 的倍数,那么这个序列被称为“K 序列”。现在要你 对数组 a 求出最长的子序列的长度,满足这个序列是 K 序列。 

输入描述:

第一行为两个整数 n, K, 以空格分隔,第二行为 n 个整数,表示 a[1] ∼ a[n],1 ≤ n ≤ 105 , 1 ≤ a[i] ≤ 109 , 1 ≤ nK ≤ 107

输出描述:

输出一个整数表示最长子序列的长度 m

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>

using namespace std;

int main()
{
	int n,k,a[100005];
	long long sum,ans;
	while(scanf("%d%d",&n,&k) != EOF)
	{
		ans = 0;
		for(int i = 0; i < n; i++)
			scanf("%d",&a[i]);
		for(int i = 0; i < n; i++)
		{
			long long sum = 0;
			for(int j = i+ans; j < n; j++)//如果令j=i;则会超时!!!!!! 
			{
				sum += a[j];
				if(sum % k == 0 && sum > k)
				{
					if(j-i+1 > ans)
						ans = j-i+1;
				} 
//				if(ans > n-i) 等同于上面的j = i+ans;
//					break; 
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

<think>好的,我现在要解决用户提到的“最长公共子字符串问题”。首先,我需要明确这个问题到底是什么意思。最长公共子字符串,听起来像是找个或多个字符串中连续相同的部分,对吧?比如“abcde”和“abcf”中的最长公共子字符串应该是“abc”,对吧?但用户可能需要更详细的解释,包括定义、应用场景、解决方法等。 首先,我应该回忆一下,子字符串和子序列的区别。子字符串必须是连续的,而子序列可以不连续。比如对于“abcde”和“aec”,最长公共子序列是“ace”,而子字符串可能只有“a”或“c”等。所以,最长公共子字符串问题确实是寻找字符串中连续相同的最长子。 接下来,用户可能需要知道如何解决这个问题。常见的解法有哪些呢?我记得暴力法、动态规划、后缀树等方法。暴力法的思路是检查所有可能的子字符串组合,然后找出最长的公共部分。但这种方法的时间复杂度很高,是O(n^4)或者O(n^3)吗?比如对于个长度为n的字符串,每个字符串有O(n²)个子字符串,然后比较这些子字符串是否相等,最坏情况下时间复杂度很高,显然不适用于长字符串。 然后是动态规划方法。动态规划通常用于优化重复子问题的情况。比如,最长公共子序列问题用动态规划可以做到O(n²)的时间复杂度。那最长公共子字符串是否也可以用类似的方法?是的,应该可以。建立一个二维数组dp,其中dp[i][j]表示以第一个字符串的第i个字符和第二个字符串的第j个字符结尾的最长公共子字符串的长度。如果当前字符相等,那么dp[i][j] = dp[i-1][j-1] + 1,否则dp[i][j] = 0。这样,遍历整个二维数组,记录最大值和位置,就能得到最长公共子字符串。这种方法的时间复杂度是O(n*m),空间复杂度也是O(n*m),其中n和m是字符串的长度。如果空间不够优化的话,可能需要用滚动数组来减少空间复杂度,因为每次只需要前一行的信息,所以可以优化到O(min(n,m))的空间。 还有一种方法是使用后缀树,构建广义后缀树,然后找到最深的共有节点,这样的方法时间复杂度是线性的,O(n+m),但实现起来比较复杂,可能在实际应用中不太常见,尤其是对于编程面试等情况,动态规划更为常见。 然后,我需要考虑如何具体实现动态规划方法。举个例子,比如字符串“abcde”和“abcf”,它们的dp表应该是怎样的呢?比如,当i=0(假设从0开始索引)时,字符是a,和第二个字符串的各个位置比较,当j=0时,a和a相等,所以dp[0][0]=1;接着,当i=1,字符是b,和第二个字符串的j=1的b相等,此时dp[1][1] = dp[0][0]+1=2,依此类推,直到i=2,字符是c,j=2的c,此时dp[2][2]=3,这时候可能最长长度是3,对应的子字符串是abc。之后遇到j=3时,字符是f,与第三个字符d不同,所以dp[3][3]=0。这样,整个过程中最大的值就是3,对应的子字符串是abc。 用户可能还关心这个问题的应用场景,比如在生物信息学中比较DNA序列的相似性,或者版本控制系统中检测文件差异,或者文本编辑器的拼写检查等。这些都是实际应用的例子。 此外,是否需要处理多个字符串的情况?最长公共子字符串问题通常讨论的是字符串的情况,但如果有多个字符串问题复杂度会大大增加,可能需要不同的方法,比如将动态规划扩展到多维,但这会导致时间和空间复杂度急剧上升,因此实际中可能采用其他优化策略。 然后,可能还要提到优化空间的方法。比如,如果使用动态规划,二维数组的空间可能比较大,可以只保留上一行的数据,或者使用一维数组,因为每次计算只需要左上的值,这样可以将空间复杂度降低到O(n)或O(m),取决于哪个更小。例如,如果字符串长度分别为m和n,那么用长度为n的数组,每次更新时从右往左或者从下往上,避免覆盖还未使用的数据。这可能需要更仔细的实现步骤。 另外,有没有其他变种问题?比如允许有k个不匹配的最长子字符串,或者寻找所有最长公共子字符串。这些可能需要不同的处理方式,但用户的问题主要集中在基本的最长公共子字符串上,所以可能暂时不需要深入讨论这些变种。 接下来,应该总结解决这个问题的步骤。首先明确问题定义,然后讲解动态规划的思路,给出状态转移方程,说明如何构建dp表,如何记录最大值及其位置,最后根据位置提取子字符串。同时,要分析时间复杂度和空间复杂度,以及可能的优化方法。 在代码实现方面,可能给出伪代码或者具体语言的例子,但用户可能只需要了解思路,所以用自然语言描述即可。例如,初始化一个二维数组,遍历字符串的每个字符,根据是否相等来更新dp值,并不断更新最大值和结束位置,最后根据结束位置和最大值长度截取子字符串。 最后,需要指出动态规划方法的优缺点。优点是思路清晰,实现相对简单,适用于中等长度的字符串;缺点是当字符串非常长时,时间和空间开销较大,此时可能需要更高效的算法如后缀树,但实现复杂。 总结起来,回答的结构应该是:问题定义、应用场景、解决方法(动态规划为主,可能提及其他方法)、实现步骤、复杂度分析以及优化空间的方法。这样用户能够逐步理解问题及其解决方案,并了解不同方法的优缺点。</think>### 最长公共子字符串问题介绍 #### 1. **问题定义** **最长公共子字符串(Longest Common Substring)** 指在个或多个字符串中,**连续相同** 的最长子。例如: - 字符串 A:`"abcde"` - 字符串 B:`"abcf"` - 最长公共子字符串为 `"abc"`(长度 3)。 > 📌 注意:子字符串要求字符连续,与子序列(允许不连续)不同。 --- #### 2. **应用场景** - **生物信息学**:DNA序列比对。 - **文本差异检测**:版本控制系统(如Git)中的文件差异分析。 - **拼写检查**:查找输入错误与正确词汇的相似部分。 --- #### 3. **解决方法** ##### **动态规划(最优常用方法)** - **核心思想**:通过二维数组记录以每个字符结尾的公共子长度。 - **状态转移方程**: $$ dp[i][j] = \begin{cases} dp[i-1][j-1] + 1 & \text{若 } A[i] = B[j] \\ 0 & \text{否则} \end{cases} $$ - `dp[i][j]`:以字符串 A 的第 `i` 个字符和字符串 B 的第 `j` 个字符结尾的最长公共子长度。 - **步骤**: 1. 初始化二维数组 `dp`,大小为 `(len(A)+1) x (len(B)+1)`。 2. 遍历所有字符对 `(i, j)`,根据字符是否相等更新 `dp[i][j]`。 3. 记录最大长度及其结束位置。 4. 根据结束位置和长度截取子字符串。 - **示例**: - A = `"abcde"`, B = `"abcf"` - `dp` 表如下(简化): | | a | b | c | f | |---|---|---|---|---| | a | 1 | 0 | 0 | 0 | | b | 0 | 2 | 0 | 0 | | c | 0 | 0 | 3 | 0 | | d | 0 | 0 | 0 | 0 | | e | 0 | 0 | 0 | 0 | - 最长子为 `"abc"`(长度 3)。 - **复杂度**: - 时间复杂度:$O(n \cdot m)$(n、m 为字符串长度)。 - 空间复杂度:$O(n \cdot m)$,可优化至 $O(\min(n, m))$(使用滚动数组)。 ##### **其他方法** - **暴力法**:枚举所有子组合并比较,时间复杂度 $O(n^3)$,不实用。 - **后缀树**:构建广义后缀树后查找最深共有节点,时间复杂度 $O(n + m)$,但实现复杂。 --- #### 4. **代码实现(Python示例)** ```python def longest_common_substring(s1, s2): m, n = len(s1), len(s2) dp = [[0]*(n+1) for _ in range(m+1)] max_len = 0 end_pos = 0 for i in range(1, m+1): for j in range(1, n+1): if s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 if dp[i][j] > max_len: max_len = dp[i][j] end_pos = i # 记录结束位置 else: dp[i][j] = 0 return s1[end_pos - max_len : end_pos] if max_len > 0 else "" ``` --- #### 5. **优化空间复杂度** 使用滚动数组(一维数组)优化空间: ```python def longest_common_substring_optimized(s1, s2): if len(s1) > len(s2): s1, s2 = s2, s1 # 确保 s1 是较短的字符串 m, n = len(s1), len(s2) dp = [0] * (m + 1) max_len = 0 end_pos = 0 for j in range(1, n+1): prev = 0 # 保存左上角的值 for i in range(1, m+1): temp = dp[i] if s1[i-1] == s2[j-1]: dp[i] = prev + 1 if dp[i] > max_len: max_len = dp[i] end_pos = i else: dp[i] = 0 prev = temp return s1[end_pos - max_len : end_pos] if max_len > 0 else "" ``` --- #### 6. **总结** - **动态规划**是解决最长公共子字符串问题的标准方法,平衡了效率和实现难度。 - 若字符串极长,可研究后缀树等高级算法,但需权衡实现复杂度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值