最长公共子序列

最长公共子序列

https://www.nowcoder.com/practice/6d29638c85bb4ffd80c020fe244baf11?tpId=188&&tqId=36860&rp=1&ru=/ta/job-code-high-week&qru=/ta/job-code-high-week/question-ranking

import java.util.*;

public class Solution {
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String s1, String s2) {
        // write code here

        if (s1.length() == 0 || s2.length() == 0) return "-1";

        int m = s1.length();
        int n = s2.length();

        int[][] dp = new int[m + 1][n + 1];
        // 标识该结果是由哪个方向转变的
        // 1 dp[i - 1][j - 1]
        // 2 dp[i - 1][j]  上方
        // 3 dp[i][j - 1] 左方
        int[][] dir = new int[m + 1][n +1]; 

        for (int i = 1; i <= m; i ++) {
            for (int j = 1; j <= n; j ++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    dir[i][j] = 1;
                } else {
                    if (dp[i - 1][j] >= dp[i][j - 1]) {
                        dp[i][j] = dp[i - 1][j]; // 上方
                        dir[i][j] = 2;
                    } else {
                        dp[i][j] = dp[i][j - 1]; // 左方
                        dir[i][j] = 3;
                    }
                }
            }
        }    

        int i = m, j = n;
        StringBuilder sb = new StringBuilder();

        // 从后往前遍历,根据转变的方向添加正确的字符,最后反转输出即可
        while (i >= 0 && j >= 0) {
            if (dir[i][j] == 1) {
                i --;
                j --;
                sb.append(s1.charAt(i));
            } 
            else if (dir[i][j] == 2) i --;
            else j --;
        }
        return sb.length() > 0 ? sb.reverse().toString() : "-1";
    }
}

思路:
先创建一个二维数组 dp,保存字符串 s1(0 -> i) 和 s2(0 -> j) 的最长公共子序列长度
在创建一个二维数组 dir, 表示 dp 数组值发生变化是,值是由 dp[i - 1][j - 1]、dp[i - 1][j]、dp[i][j - 1]变化而来的。

遍历字符串 s1、s2,当 s1.charAt(i - 1) == s2.charAt(j - 1) 时,最长公共子序列长度 + 1,dir[i][j] = 1;
当 s1.charAt(i - 1) != s2.charAt(j - 1) 时,若 dp[i - 1][j] >= dp[i][j - 1], 则说明上面的值比下面的值大,
dp[i][j] = dp[i - 1][j], dir[i][j] = 2; 否则说明左边的值比上方的值大,dir[i][j] = 3。

最后从后往前遍历字符串,根据字符串转变的方向将之添加入结果中,最后将结果反转输出即可。
图片说明

全部评论

相关推荐

10-24 13:36
门头沟学院 Java
Zzzzoooo:更新:今天下午有hr联系我去不去客户端,拒了
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
1
1
分享
牛客网
牛客企业服务