#P2404. 第1题-D路通信
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 604
            Accepted: 172
            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 。