๐Ÿ“Œ About

lcs gif.gif

LCS algorithm์€ ๋‘ ๊ฐ€์ง€๋กœ ํ•ด์„์ด ๋œ๋‹ค. Longest Common Subsequence์™€ Longest Common Substring์ด๋‹ค. Subsequence์€ ๋ฌธ์ž์—ด์˜ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด๋“ค์˜ ์กฐํ•ฉ์ด ๊ฐ€์žฅ ๊ธธ๊ฒŒ ๊ฐ™์€ ๋‘ ๋ฌธ์ž์—ด์˜ ๊ณตํ†ต ๋ถ€๋ถ„์„ ์ด์•ผ๊ธฐ ํ•œ๋‹ค. Substring์€ ๋ฌธ์ž์—ด์˜ ํ•œ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์ด ๊ฐ€์žฅ ๊ธธ๊ฒŒ ๊ฐ™์€ ๋‘ ๋ฌธ์ž์—ด์˜ ๊ณตํ†ต ๋ถ€๋ถ„์„ ์ด์•ผ๊ธฐํ•œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” subsequence๋ฅผ ์ด์•ผ๊ธฐํ•œ๋‹ค.

Untitled

๐Ÿ“Œ Algorithm

๐Ÿ“ Longest Common Subsequence

Step 0. ๋ฌธ์ž์—ด A์™€ ๋ฌธ์ž์—ด B์˜ ๊ธธ์ด์— ๋”ฐ๋ผ LCS ๋ฐฐ์—ด์„ ์ƒ์„ฑ

private final String strA;
private final String strB;

private int[][] lcs;

private void initializeLCSArray() {
    lcs = new int[strA.length() + 1][strB.length() + 1];
}

Step 1. ๋ฌธ์ž์—ด A์™€ ๋ฌธ์ž์—ด B๋ฅผ ์•ž์—์„œ๋ถ€ํ„ฐ ํ•œ ๋ฌธ์ž์”ฉ ๋น„๊ต

Step 1-1. ๋‘ ๋ฌธ์ž๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉด LCS[i - 1][j], LCS{i][j - 1] ์ค‘ ํฐ๊ฐ’์„ ์ €์žฅ

Step 1-2. ๋‘ ๋ฌธ์ž๊ฐ€ ๊ฐ™๋‹ค๋ฉด LCS[i - 1][j - 1] + 1 ์ €์žฅ

private void compareChars() {
    for (int i = 1; i <= strA.length(); i++)
        for (int j = 1; j <= strB.length(); j++)
            lcs[i][j] = strA.charAt(i - 1) == strB.charAt(j - 1) ?
                    lcs[i - 1][j - 1] + 1 :
                    Math.max(lcs[i - 1][j], lcs[i][j - 1]);
}

Step 2. ๊ณตํ†ต ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ์ฐพ๊ธฐ (0์œผ๋กœ ์ด๋™ํ•˜๋ฉด ์ข…๋ฃŒ)

Step 2-1. LCS ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ๊ฐ’๋ถ€ํ„ฐ ํƒ์ƒ‰

Step 2-2. LCS[i - 1][j]์™€ LCS[i][j _ 1] ์ค‘ ๊ฐ™์€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ๊ฐ’์œผ๋กœ ์ด๋™

Step 2-3. ๊ฐ™์€๊ฐ’์ด ์—†์œผ๋ฉด ๋ฌธ์ž๋ฅผ ๊ณตํ†ต ๋ถ€๋ถ„์— ์ถ”๊ฐ€ํ•˜๊ณ  i - 1, j - 1 ์ด๋™

private String findCommonString() {
    StringBuilder builder = new StringBuilder();
    int i = strA.length();
    int j = strB.length();
    while (lcs[i][j] != 0) {
        if (lcs[i - 1][j] == lcs[i][j]) i--;
        else if (lcs[i][j - 1] == lcs[i][j]) j--;
        else {
            builder.append(strA.charAt(i - 1));
            i--;
            j--;
        }
    }
    return builder.reverse().toString();
}

๐Ÿ“ Longest Common Substring

LCS(Substring)์€ LCS(Subsequence)์—์„œ ๋‘ ๋ฌธ์ž๊ฐ€ ๋‹ค๋ฅผ ๋•Œ๋งŒ 0์œผ๋กœ ์ €์žฅํ•˜๋ฉด ๋œ๋‹ค.

์ถ”๊ฐ€๋กœ substring์€ ์ตœ์žฅ ๊ธธ์ด ํƒ์ƒ‰์„ ํ•˜๋ฉด์„œ ๋™์‹œ์— ์ตœ์žฅ ๊ณตํ†ต ๋ฌธ์ž์—ด์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

private String compareSubstringChars() {
    String common = "";
    for (int i = 1; i <= strI.length(); i++) {
        for (int j = 1; j <= strJ.length(); j++) {
            if (strI.charAt(i - 1) == strJ.charAt(j - 1)) {
                lcs[i][j] = lcs[i - 1][j - 1] + 1;
                String string = strI.substring(i - lcs[i][j], i);
                if (common.length() < string.length()) common = string;
            }
        }
    }
    return common;
}

๐Ÿ“Œ Java Code

๐Ÿ“ Longest Common Subsequence

public class LCS {

    private final String strA;
    private final String strB;

    private int[][] lcs;

    public LCS(String strA, String strB) {
        this.strA = strA;
        this.strB = strB;
    }

    public String runSubsequence() {
        initializeLCSArray();
        compareChars();
        return findCommonString();
    }

    private void initializeLCSArray() {
        lcs = new int[strA.length() + 1][strB.length() + 1];
    }

    private void compareChars() {
        for (int i = 1; i <= strA.length(); i++)
            for (int j = 1; j <= strB.length(); j++)
                lcs[i][j] = strA.charAt(i - 1) == strB.charAt(j - 1) ?
                        lcs[i - 1][j - 1] + 1 :
                        Math.max(lcs[i - 1][j], lcs[i][j - 1]);
    }

    private String findCommonString() {
        StringBuilder builder = new StringBuilder();
        int i = strA.length();
        int j = strB.length();
        while (lcs[i][j] != 0) {
            if (lcs[i - 1][j] == lcs[i][j]) i--;
            else if (lcs[i][j - 1] == lcs[i][j]) j--;
            else {
                builder.append(strA.charAt(i - 1));
                i--;
                j--;
            }
        }
        return builder.reverse().toString();
    }
}

๐Ÿ“ Longest Common Substring