最長共通部分系列長(LCS)を求めるJavaプログラム

素朴に実装。LCS長が何たるかは別のページを参照してください。

LCSのアルゴリズムは、系列Xのi番目をxi、系列Yのj番目をyjとすると、

  • i = 0 または j = 0 のとき、
    • LCS(i, j) = 0
  • i, j > 0 かつ xi == yj のとき、
    • LCS(i, j) = LCS(i-1, j-1) + 1
  • i, j > 0 かつ xi != yj のとき、
    • LCS(i, j) = max(LCS(i-1, j), LCS(i, j-1))

ですが、Javaは配列が0オリジンなので、このまま素直に実装してしまうと系列XとYの一文字目が一致した場合でもLCS長が0になってしまいます。そこでちょっとトリッキーな実装にしてみました。

public class LongestCommonSubsequence {

	// 実行サンプル
	public static void main(String[] args) {
		System.out.println(LCS_Length("ABCBDAB", "BDCABA"));
	}

	private static int LCS_Length(String str1, String str2) {
		int len1 = str1.length(), len2 = str2.length();
		int[][] lcs_table = new int[len1][len2]; // LCS長を格納した表
		
		for (int i = 0; i < len1; i++) {
			for (int j = 0; j < len2; j++) {
				if (str1.charAt(i) == str2.charAt(j))
					lcs_table[i][j] = ((i == 0 || j == 0) ? 0 : lcs_table[i-1][j-1]) + 1;
				else if (str1.charAt(i) != str2.charAt(j))
					lcs_table[i][j] = Math.max(
							i == 0 ? 0 : lcs_table[i-1][j],
							j == 0 ? 0 : lcs_table[i][j-1]);
			}
		}
		
		// LCS表の表示
//		for (int i = 0; i < len1; i++) {
//			for (int j = 0; j < len2; j++)
//				System.out.print(lcs_table[i][j] + " ");
//			System.out.println();
//		}
		
		// LCS表の最も右下にLCS長が格納されている
		return lcs_table[len1-1][len2-1];
	}
}