1 solutions

  • 1
    @ 8 months ago

    思路

    最长公共子串

    简化题意

    给定两个字符串 sstt,问两个字符串的最长公共子串长度。

    ss 的长度为 nntt 的长度为 mm

    暴力做法

    枚举 tt 的每个子串是否在 ss 中找到,即朴素的字符串匹配算法,每次匹配是 O(nm)O(nm) 的。 枚举每个 tt 的子串,则是以 tt 的每个索引开始,依次和 ss 进行比较,如果存在 tt 的某个字符和对应的 ss 的字符不匹配了,则说明后续也不会匹配了,这样的复杂度为 O(nm2)O(nm^2)

    优化暴力做法

    dp[i][j]dp[i][j] 表示以 s[i]s[i]t[j]t[j] 结尾的子字符串的相同的最大长度。 如果 dp[i][j]=k(k1)dp[i][j]=k(k\geq 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][j] 是从 dp[i1][j1]dp[i-1][j-1] 转移而来的。

    状态转移方程为:dp[i][j]=dp[i1][j1]+1dp[i][j]=dp[i-1][j-1]+1

    最后取所有 dp[i][j]dp[i][j]max\max 即可。

    类似题目推荐

    LeetCode

    1. 72. 编辑距离
    2. 1143. 最长公共子序列
    3. 14. 最长公共前缀

    Codefun2000

    1. 字节跳动 暑期实习-2023.03.24-第二题-元素骰子

    2. 招行 2023.04.09-招行-第二题-特殊的01串

    3. 华为 P1025. 2022.11.9-攻城战

    代码

    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);
    });
    
    • 1

    Information

    ID
    10
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    3
    Tags
    # Submissions
    178
    Accepted
    44
    Uploaded By