题解 | #最长公共子串#

最长公共子串

http://www.nowcoder.com/practice/f33f5adc55f444baa0e0ca87ad8a6aac


package com.hhdd.dp;

import com.hhdd.最长公共前缀;

/**
 * 给定两个字符串str1和str2,输出两个字符串的最长公共子串
 * 题目保证str1和str2的最长公共子串存在且唯一。
 * <p>
 * 数据范围: 1 \le |str1|,|str2| \le 50001≤∣str1∣,∣str2∣≤5000
 * 要求: 空间复杂度 O(n^2)O(n
 * 2
 * ),时间复杂度 O(n^2)O(n
 * 2
 * )
 * 输入:
 * "1AB2345CD","12345EF"
 * 复制
 * 返回值:
 * "2345"
 *
 * @Author HuangLusong
 * @Date 2022/4/1 21:46
 */
public class 最长公共子串 {
    /**
     * longest common substring
     * <p>
     * <p>
     * 先暴力做吧
     *
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    public String LCS(String str1, String str2) {
        // write code here
        if (str1.length() == 0 || str2.length() == 0) {
            return null;
        }
        String longer = "";
        String shorter = "";
        if (str1.length() > str2.length()) {
            longer = str1;
            shorter = str2;
        } else {
            longer = str2;
            shorter = str1;
        }
        String res = "";
        //遍历shorter
        for (int i = 0; i < shorter.length(); i++) {
            for (int j = i + 1; j <= shorter.length(); j++) {
                String temp = shorter.substring(i, j);
                if (longer.indexOf(temp) != -1) {
                    if (temp.length() > res.length()) {
                        res = temp;
                    }
                } else {
                    break;
                }
            }
        }
        return res;
    }

    /**
     * 从线到面的思考
     *
     * @param str1
     * @param str2
     * @return
     */
    public String LCS2(String str1, String str2) {
        // write code here
        if (str1.length() == 0 || str2.length() == 0) {
            return null;
        }
        int[][] flags = new int[str1.length()][str2.length()];

        for (int i = 0; i < str1.length(); i++) {
            for (int j = 0; j < str2.length(); j++) {
                // 遍历如果对应位置的字符串相等则将标志1存入flags
                if (str1.charAt(i) == str2.charAt(j)) {
                    flags[i][j] = 1;
                }
            }
        }
        // 直接遍历flags
        // 很容易知道所谓的子串其实就是斜线,找出最长的斜线即可
        /**
         * 如果最终resRow还是-1则说明根本没找到
         */
        int resRow = -1;
        int resLength = 0;
        for (int i = 0; i < str1.length(); i++) {
            for (int j = 0; j < str2.length(); j++) {
                if (flags[i][j] == 1) {
                    int tempLength = 0;
                    int tempI = i;
                    int tempJ = j;
                    while (tempI < str1.length() && tempJ < str2.length()) {
                        if (flags[tempI][tempJ] == 1) {
                            tempLength++;
                        } else {
                            break;
                        }
                        tempI++;
                        tempJ++;
                    }
                    if (tempLength > resLength) {
                        resLength = tempLength;
                        resRow = i;
                    }
                }
            }
        }
        if (resLength == 0) {
            return "";
        }
        return str1.substring(resRow, resRow + resLength);
    }

    /**
     * 通过dp找规律的方式解决,比较难想
     * dp[i][j] 表示str1和str2分别以最后i,j位置为结束的最大公共子串长度
     * 很显然i,j位置的字符必须相等
     * 递推公式dp[i][j]=dp[i-1][j-1]+1
     *
     * @param str1
     * @param str2
     * @return
     */
    public String LCS3(String str1, String str2) {
        if (str1.length() == 0 || str2.length() == 0) {
            return null;
        }
        int[][] dp = new int[str1.length()][str2.length()];
        //设置几个变量存值
        int resRow = -1;
        int resLength = 0;
        //把边界位置初始化得了,简单点
        for (int i = 0; i < str1.length(); i++) {
            if (str1.charAt(i) == str2.charAt(0)) {
                dp[i][0] = 1;
                if (dp[i][0] > resLength) {
                    resLength = dp[i][0];
                    resRow = i;
                }
            }
        }
        for (int i = 0; i < str2.length(); i++) {
            if (str2.charAt(i) == str1.charAt(0)) {
                dp[0][i] = 1;
                if (dp[0][i] > resLength) {
                    resLength = dp[0][i];
                    resRow = 0;
                }
            }
        }

        for (int i = 1; i < str1.length(); i++) {
            for (int j = 1; j < str2.length(); j++) {
                if (str1.charAt(i) != str2.charAt(j)) {
                    // 本身就是0......
                } else {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    if (dp[i][j] > resLength) {
                        resLength = dp[i][j];
                        resRow = i;
                    }
                }
            }
        }
        return str1.substring(resRow + 1 - resLength, resRow + 1);

    }


    public static void main(String[] args) {
        最长公共子串 demo = new 最长公共子串();
        String res = demo.LCS3("abcdefg", "ab1cdefgabc1defg");
        System.out.println("res = " + res);
    }

}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务