2020-12-29今日のNiuke =最長共通部分列+最長共通部分列

出典:リンク:
免責事項:私が誰かの権利を侵害した場合は、私に連絡してください。削除します。
専門家を歓迎して私にスプレーしてください。

最長の一般的な部分文字列のタイトルの説明

リンク:https//www.nowcoder.com/practice/f33f5adc55f444baa0e0ca87ad8a6aac?tpId = 188 && tqId = 36892&rp = 1&ru = / ta / job-code-high-week&qru = / ta / job-code-high- week / question-ranking

2つの文字列str1とstr2を指定して、2つの文字列の最長の共通部分文字列を出力します。最長の共通部分文字列が空の場合は、-1を出力します。

例1
「1AB2345CD」と入力すると、「12345EF」
は値「2345」を返します。

最長の一般的な部分文字列コード:

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) {
       if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){
           return "-1";
       } 
        int indexMax = 0;
        int maxLen = 0;
        int m = str1.length();
        int n = str2.length();

        //dp[i][j]代表 str1[0~i-1]和str2[0~j-1] 的最长公共子串的长度  
        int[][] dp = new int[m][n];
        for(int i = 0; i < m; ++ i){
            for(int j = 0; j < n; ++j){
                if(str1.charAt(i) == str2.charAt(j)){
                    if(i == 0 || j == 0){
                        dp[i][j] = 1;
                    }else{
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    }
                }//else 是str1[i]!=str2[j]的情况,这种情况下dp[i][j]=0,由于初始化已经将其设置为0,所以这里不再写。
                
                 //处理完dp[i][j]之后,查看一下是否需要记录下来
                if(maxLen < dp[i][j]){
                    maxLen = dp[i][j]; //记录下最长公共子串的长度
                    indexMax = i; //记录下出现“最长公共子串”时的末尾字符的位置
                }
            }
        }
        if(maxLen == 0) return "-1";
        //字符串截取的长度有(end-start+1) = maxLen, 那么start = indexMax +1-maxLen
        // maxLen即为所截取的字符串的长度。
        return str1.substring(indexMax - maxLen  + 1 , indexMax + 1);
    }
}

最長共通部分列タイトルの説明

リンク: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

2つの文字列str1とstr2が与えられた場合、文字列の最長共通部分列を出力します。最長共通部分列が空の場合、-1が出力されます。

例1
「1A2C3D4B56」、「B1D23CA45B6A」を入力し、
戻り値「123456」
は、「123456」と「12C4B6」が最長共通部分列であることを示し、いずれか1つが出力されます。

最長共通部分列コード

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
       int str1Len = s1.length();
        int str2Len = s2.length();
        int[][] cLenNUm = new int[s1.length() + 1][s2.length() + 1];//默认赋值,[0][?],[?][0]默认两侧皆0,类似公式中0的场景
        //构造一个LCS长度数组
        for (int i = 1; i <= str1Len; i++) {
            for (int j = 1; j <= str2Len; j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {//对应公式第二条相等
                    cLenNUm[i][j] = cLenNUm[i - 1][j - 1] + 1;
                } else {//对应公式第三条不相等
                    cLenNUm[i][j] = Math.max(cLenNUm[i][j - 1], cLenNUm[i - 1][j]);
                }
            }
        }

        //反推结果
        int i = str1Len;
        int j = str2Len;
        StringBuffer sb = new StringBuffer();//作为结果
        while (i > 0 && j > 0) {//这里其实处理了i=0,j=0的,对应公式0的反推场景
            if (s1.charAt(i - 1) == s2.charAt(j - 1)) {//反推公式中不相等的场景
                //该值一定是被选取到的,根据之前的公式,知道两条字符串的下标都前进一位
                sb.append(s1.charAt(i - 1));
                i--;
                j--;
            } else {//对应公式中不相等的反推场景
                if (cLenNUm[i][j - 1] > cLenNUm[i - 1][j]) {//找大的那个方向,此处是左边大于上面,则该处的结果是来自左边
                    j--;
                } else if (cLenNUm[i][j - 1] < cLenNUm[i - 1][j]) {
                    i--;
                } else if (cLenNUm[i][j - 1] == cLenNUm[i - 1][j]) {
                    //对于有分支的可能时,我们选取单方向
                    j--;   //此结果对于结果1所选取方向,str1的下标左移一位.替换为j--,则结果对应与结果2选取的方向
                }
            }
        }
        //由于是从后往前加入字符的,需要反转才能得到正确结果
        return sb.reverse().toString();
    }
}

どちらの質問も動的計画法です

最も長い一般的な部分文字列:ここで必要な部分文字列の文字は次のとおりです他の文字の間にスペースはありません

int[][] dp = new int[len1+1][len2+1];
        dp[0][0] = 0;
        int maxlen = Integer.MIN_VALUE, indexmax = -1;
        for(int i=0;i<len1;++i){
            for(int j=0;j<len2;++j){
                if(str1.charAt(i) == str2.charAt(j)){
                    if(i == 0 ||j == 0) dp[i][j] = 1;
                    else dp[i][j] = dp[i-1][j-1] + 1;
                }
                if(maxlen < dp[i][j]){
                    maxlen = dp[i][j];
                    indexmax = i;
                }
            }
        }

ここで共通の部分文字列にある最長の部分列他の文字の間隔を空けることができます

int[][] dp = new int[len1+1][len2+1];
        dp[0][0] = 0;
        for(int i=1;i<=len1;++i){
            for(int j=1;j<=len2;++j){
                if(s1.charAt(i-1) == s2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1]+1;
                }else{
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }

おすすめ

転載: blog.csdn.net/qq_45531729/article/details/111935433