#P2404. 第1题-D路通信
-
1000ms
Tried: 608
Accepted: 175
Difficulty: 3
所属公司 :
华为
时间 :2022年10月12日-国内
-
算法标签>动态规划
第1题-D路通信
思路
最长公共子串
简化题意
给定两个字符串 s 和 t,问两个字符串的最长公共子串长度。
s 的长度为 n ,t 的长度为 m
暴力做法
枚举 t 的每个子串是否在 s 中找到,即朴素的字符串匹配算法,每次匹配是 O(nm) 的。 枚举每个 t 的子串,则是以 t 的每个索引开始,依次和 s 进行比较,如果存在 t 的某个字符和对应的 s 的字符不匹配了,则说明后续也不会匹配了,这样的复杂度为 O(nm2) 。
优化暴力做法
dp[i][j] 表示以 s[i] 和 t[j] 结尾的子字符串的相同的最大长度。 如果 dp[i][j]=k(k≥1),必然有 $s[i-k+1]=t[j-k+1],s[i-k+2]=t[j-k+2],\cdots s[i]=t[j]$。故 dp[i][j] 是从 dp[i−1][j−1] 转移而来的。
状态转移方程为:dp[i][j]=dp[i−1][j−1]+1
最后取所有 dp[i][j] 的 max 即可。
类似题目推荐
LeetCode
Codefun2000
代码
CPP
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N][N];
char s[N], t[N];
int ns, nt;
int main()
{
scanf("%s%s", s + 1, t + 1);
ns = strlen(s + 1), nt = strlen(t + 1);
// 最长公共子串
int ans = 0;
// 枚举 s 中子串的最后一个字符
for (int i = 1; i <= ns; ++i) {
// 枚举 t 中子串的最后一个字符
for (int j = 1; j <= nt; ++j) {
// 如果两个尾字符相等,才会有长度至少为 1 的公共子串
if (s[i] == t[j]) {
// 状态转移
f[i][j] = f[i - 1][j - 1] + 1;
// 更新答案
ans = max(ans, f[i][j]);
}
}
}
printf("%d\n", ans);
}
python
N = 1010
f = [[0]*N for _ in range(N)]
s = input().strip()
t = input().strip()
ns, nt = len(s), len(t)
# 最长公共子串
ans = 0
# 枚举 s 中子串的最后一个字符
for i in range(1, ns+1):
# 枚举 t 中子串的最后一个字符
for j in range(1, nt+1):
# 如果两个尾字符相等,才会有长度至少为 1 的公共子串
if s[i-1] == t[j-1]:
# 状态转移
f[i][j] = f[i-1][j-1] + 1
# 更新答案
ans = max(ans, f[i][j])
print(ans)
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = 1010;
int[][] f = new int[N][N];
char[] s = scan.next().toCharArray();
char[] t = scan.next().toCharArray();
int ns = s.length, nt = t.length;
// 最长公共子串
int ans = 0;
// 枚举 s 中子串的最后一个字符
for (int i = 1; i <= ns; ++i) {
// 枚举 t 中子串的最后一个字符
for (int j = 1; j <= nt; ++j) {
// 如果两个尾字符相等,才会有长度至少为 1 的公共子串
if (s[i-1] == t[j-1]) {
// 状态转移
f[i][j] = f[i - 1][j - 1] + 1;
// 更新答案
ans = Math.max(ans, f[i][j]);
}
}
}
System.out.println(ans);
}
}
Go
package main
import (
"fmt"
)
func main() {
const N int = 1010
var f [N][N]int
var s, t string
fmt.Scan(&s, &t)
ns, nt := len(s), len(t)
// 最长公共子串
ans := 0
// 枚举 s 中子串的最后一个字符
for i := 1; i <= ns; i++ {
// 枚举 t 中子串的最后一个字符
for j := 1; j <= nt; j++ {
// 如果两个尾字符相等,才会有长度至少为 1 的公共子串
if s[i-1] == t[j-1] {
// 状态转移
f[i][j] = f[i-1][j-1] + 1
// 更新答案
if f[i][j] > ans {
ans = f[i][j]
}
}
}
}
fmt.Println(ans)
}
Js
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
input += data;
return;
});
process.stdin.on('end', () => {
const lines = input.trim().split('\n');
const N = 1010;
const f = new Array(N).fill().map(() => new Array(N).fill(0));
const s = lines[0];
const t = lines[1];
const ns = s.length, nt = t.length;
// 最长公共子串
let ans = 0;
// 枚举 s 中子串的最后一个字符
for (let i = 1; i <= ns; ++i) {
// 枚举 t 中子串的最后一个字符
for (let j = 1; j <= nt; ++j) {
// 如果两个尾字符相等,才会有长度至少为 1 的公共子串
if (s[i-1] == t[j-1]) {
// 状态转移
f[i][j] = f[i - 1][j - 1] + 1;
// 更新答案
ans = Math.max(ans, f[i][j]);
}
}
}
console.log(ans);
});
题目内容
塔子与兔子两个兄弟刚学完计算机网络原理课程。他们对通信这一概念有位好奇。现在老师给了他们一个D路通信。他们面对的通信链路有如下几个性质:
- 高斯噪声性: 如果发出一段字符串作为消息,消息的开始前和结束后可能会出现随机高斯噪声;
- 内容完整性: 该过程不会丢失任何字符,字符顺序也不会发生变化;
- 字符统一性: 所有的消息内容和噪声都是小写字符;
依据链路的特点,他们俩想到了一种消除高斯噪声的算法:
- 同时采用两条含有随机噪声的链路发出一段消息。
- 在接收侧,在接收到的两条消息当中寻找最长的那段连续公共子串,就是有效信息。
现在小明想求有效消息的长度,注意有效消息不一定是唯一的,也有可能为空, 只要求返回消息的长度,
输入描述
两行分别代表两个字符串,分别为两条链路收到的信息,仅包含小写字母。
0<len≤1000
输出描述
一行。
一个数字,以回车结束,表示有效信息的长度。
样例
样例一:
输入
vsavvzxaaxvzvz
zzczcaaa
输出
2
样例解释:
两条信息中,最长的公共字符串是 aa ,长度为 2 。
样例二:
输入
tttazitazittz
tazittttt
输出
6
样例解释:
两条信息中,最长的公共字符串是 tazitt ,长度为 6 。