19、最长公共子串

描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。

数据范围: 1≤∣str1∣,∣str2∣≤50001 \le |str1|,|str2| \le 5000 1≤∣str1∣,∣str2∣≤5000
要求: 空间复杂度 O(n2)O(n^2)O(n2),时间复杂度 O(n2)O(n^2)O(n2)
示例1

输入: “1AB2345CD”,“12345EF”
返回值: “2345”

备注

1≤∣str1∣,∣str2∣≤5 0001 \leq |str_1|, |str_2| \leq
5,0001≤∣str1​∣,∣str2​∣≤5000

注意这题求的是最长公共子串,不是最长公共子序列,子序列可以是不连续的,但子串一定是连续的。

定义dp[i][j]表示字符串str1中第i个字符和str2种第j个字符为最后一个元素所构成的最长公共子串。如果要求dp[i][j],也就是str1的第i个字符和str2的第j个字符为最后一个元素所构成的最长公共子串,我们首先需要判断这两个字符是否相等。

如果不相等,那么他们就不能构成公共子串,也就是
dp[i][j]=0;

如果相等,我们还需要计算前面相等字符的个数,其实就是dp[i-1][j-1],所以
dp[i][j]=dp[i-1][j-1]+1;

具体做法:

step 1:我们可以用dp[i][j]dp[i][j]dp[i][j]表示在str1中以第iii个字符结尾在str2中以第jjj个字符结尾时的公共子串长度,
step 2:遍历两个字符串填充dp数组,转移方程为:如果遍历到的该位两个字符相等,则此时长度等于两个前一位长度+1,dp[i][j]=dp[i−1][j−1]+1dp[i][j] = dp[i - 1][j - 1] + 1dp[i][j]=dp[i−1][j−1]+1,如果遍历到该位时两个字符不相等,则置为0,因为这是子串,必须连续相等,断开要重新开始。
step 3:每次更新dp[i][j]dp[i][j]dp[i][j]后,我们维护最大值,并更新该子串结束位置。
step 4:最后根据最大值结束位置即可截取出子串。

转移方程为:如果遍历到的该位两个字符相等,则此时长度等于两个前一位长度+1,dp[i][j]=dp[i−1][j−1]+1,如果遍历到该位时两个字符不相等,则置为0,因为这是子串,必须连续相等,断开要重新开始。

import java.util.*;


public class Solution {
    /**
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String str1, String str2) {
        // write code here
        //1、用dp[i][j]表示str1中第i字符结尾,在str2中以第j字符结尾时公共子串长度
        int[][] dp = new int[str1.length() + 1][str2.length() + 1];
        //2、定义整型max,pos,并赋值为0
        int max = 0;
        int pos = 0;
        //3、遍历两个字符串填充dp数组
        for (int i = 1; i <= str1.length(); i++) {
            for (int j = 1; j <= str2.length(); j++) {
                //4、如果该两位相同
                if (str1.charAt(i - 1) == str2.charAt(j - 1))
                    //5、则此时长度等于两个前一位长度+1,
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                //6、否则
                else
                    //7、该位置为0,这是子串,必须连续相等,断开要重新开始
                    dp[i][j] = 0;

                //8、更新最大长度.如果dp大于最大,将dp赋值给最大,pos在i-1
                if (dp[i][j] > max) {
                    max = dp[i][j];
                    pos = i - 1;
                }

            }
        }
        //9、最后根据最大值结束位置即可截取出子串
        return str1.substring(pos - max + 1, pos + 1);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值