|
1 | 1 | package algorithms.dynamic
|
| 2 | + |
| 3 | +/// Longest Common Subsequence (LCS) Algorithm |
| 4 | +/// Computes the length and reconstructs the LCS of two sequences using dynamic programming. |
| 5 | +/// |
| 6 | +/// Uses a 2D table to store LCS values for substrings of A and B. |
| 7 | +/// |
| 8 | +/// Time Complexity: O(n * m), where n and m are the lengths of the input sequences. |
| 9 | + |
| 10 | +def LCS(A: Array[Char], B: Array[Char]): (Array[Array[Int]], Int, String) = { |
| 11 | + val n = A.length |
| 12 | + val m = B.length |
| 13 | + |
| 14 | + val L: Array[Array[Int]] = Array.fill(n + 1, m + 1)(0) |
| 15 | + |
| 16 | + // Fill the DP table |
| 17 | + for (i <- 1 to n) { |
| 18 | + for (j <- 1 to m) { |
| 19 | + if (A(i - 1) == B(j - 1)) { |
| 20 | + L(i)(j) = L(i - 1)(j - 1) + 1 |
| 21 | + } else { |
| 22 | + L(i)(j) = Math.max(L(i - 1)(j), L(i)(j - 1)) |
| 23 | + } |
| 24 | + } |
| 25 | + } |
| 26 | + |
| 27 | + // LCS Length |
| 28 | + val lcsLength = L(n)(m) |
| 29 | + |
| 30 | + // Reconstruct the LCS string |
| 31 | + val lcsBuilder = new StringBuilder() |
| 32 | + var i = n |
| 33 | + var j = m |
| 34 | + while (i > 0 && j > 0) { |
| 35 | + if (A(i - 1) == B(j - 1)) { |
| 36 | + lcsBuilder.append(A(i - 1)) |
| 37 | + i -= 1 |
| 38 | + j -= 1 |
| 39 | + } else if (L(i - 1)(j) > L(i)(j - 1)) { |
| 40 | + i -= 1 |
| 41 | + } else { |
| 42 | + j -= 1 |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + (L, lcsLength, lcsBuilder.reverse.toString) |
| 47 | +} |
| 48 | + |
| 49 | +@main |
| 50 | +def lcsMain(): Unit = { |
| 51 | + val x: Array[Char] = Array('A', 'L', 'G', 'O', 'R', 'I', 'T', 'H', 'M') |
| 52 | + val y: Array[Char] = Array('A', 'L', 'T', 'R', 'U', 'I', 'S', 'T', 'I', 'C') |
| 53 | + |
| 54 | + val (mat, res, lcs) = LCS(x, y) |
| 55 | + mat.foreach(row => println(row.mkString(" "))) |
| 56 | + println(s" The Longest subsequence has length : $res ") |
| 57 | + println(s" The Longest subsequence is : $lcs") |
| 58 | +} |
0 commit comments