Skip to content
Snippets Groups Projects
Verified Commit 9ca184b3 authored by Dmytro Bogatov's avatar Dmytro Bogatov :two_hearts:
Browse files

Solve LCS.

parent 1645bc63
Branches
No related tags found
No related merge requests found
using System.Collections.Generic;
using System.Linq;
namespace CodingInterview.HackerRank
{
/// <summary>
......
using System;
using System.Collections.Generic;
using System.Linq;
namespace CodingInterview.HackerRank
{
/// <summary>
/// A subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.
/// Longest common subsequence (LCS) of 2 sequences is a subsequence, with maximal length, which is common to both the sequences.
///
/// Given two sequences of integers, A = [a[1], a[2], ... , a[n]] and B = [b[1], b[2], ... , b[m]], find the longest common subsequence and print it as a line of space-separated integers.
/// If there are multiple common subsequences with the same maximum length, print any one of them.
///
/// In case multiple solutions exist, print any of them.
/// It is guaranteed that at least one non-empty common subsequence will exist.
///
/// https://www.hackerrank.com/challenges/dynamic-programming-classics-the-longest-common-subsequence/problem
/// </summary>
public class LCS
{
/// <summary>
/// Returns an integer array of a longest common subsequence.
/// </summary>
/// <param name="a">first sequence</param>
/// <param name="b">second sequence</param>
/// <returns>longest common subsequence</returns>
public int[] Solve(int[] a, int[] b)
{
// DP table
// going in a direction represents moving along that sequence
// an element in the table is an LCS of the sequences represented by coordinates
List<int>[,] DP = new List<int>[a.Length, b.Length];
// A wrapper that checks that coordinates are valid
Func<int, int, List<int>> getDP =
(int i, int j) =>
{
if (i < 0 || j < 0)
{
return new List<int>();
}
return DP[i, j];
};
// LCS so far
List<int> best = new List<int>();
for (int i = 0; i < a.Length; i++)
{
for (int j = 0; j < b.Length; j++)
{
// if the elements are equal we advance both sequences and remember that element
if (a[i] == b[j])
{
DP[i, j] = new List<int>(getDP(i - 1, j - 1));
DP[i, j].Add(a[i]);
}
// otherwise we use the best LCS of either of two sequences
else
{
DP[i, j] = new List<int>(getDP(i - 1, j).Count > getDP(i, j - 1).Count ? getDP(i - 1, j) : getDP(i, j - 1));
}
// remember to track the best one
if (getDP(i, j).Count > best.Count)
{
best = new List<int>(getDP(i, j));
}
}
}
return best.ToArray();
}
}
}
using Xunit;
namespace CodingInterview.Tests.HackerRank
{
public class LCS
{
[Fact]
public void TestCases()
{
void checkSolution(int[] a, int[] b, int lcsLength)
{
bool isSubSequence(int[] subseq, int[] seq)
{
int j = 0;
for (int i = 0; i < seq.Length && j < subseq.Length; i++)
{
if (subseq[j] == seq[i])
{
j++;
}
}
return (j == subseq.Length);
}
var lcs = new CodingInterview.HackerRank.LCS().Solve(a, b);
Assert.Equal(lcsLength, lcs.Length);
Assert.True(isSubSequence(lcs, a));
Assert.True(isSubSequence(lcs, b));
}
// From Hacker Rank
checkSolution(
new int[] { 1, 2, 3, 4, 1 },
new int[] { 3, 4, 1, 2, 1, 3 },
3
);
checkSolution(
new int[] { 3, 9, 8, 3, 9, 7, 9, 7, 0 },
new int[] { 3, 3, 9, 9, 9, 1, 7, 2, 0, 6 },
6
);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment