Skip to content

Commit d35b15e

Browse files
authored
Add Longest Common Subsequence in Pascal (TheRenegadeCoder#4836)
1 parent 6f1ac8a commit d35b15e

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
program LongestCommonSubsequence;
2+
3+
{$mode objfpc}{$H+}
4+
5+
uses
6+
Generics.Collections,
7+
SysUtils;
8+
9+
type
10+
TIntegerList = specialize TList<integer>;
11+
12+
procedure ShowUsage;
13+
begin
14+
Writeln('Usage: please provide two lists in the format "1, 2, 3, 4, 5"');
15+
Halt(1);
16+
end;
17+
18+
function ParseIntegerList(const S: string): TIntegerList;
19+
var
20+
Tokens: TStringArray;
21+
Token: string;
22+
Value: integer;
23+
begin
24+
if S.Trim = '' then
25+
ShowUsage;
26+
27+
Tokens := S.Split([',']);
28+
if Length(Tokens) = 0 then
29+
ShowUsage;
30+
31+
Result := TIntegerList.Create;
32+
for Token in Tokens do
33+
begin
34+
if not TryStrToInt(Trim(Token), Value) then
35+
begin
36+
Result.Free;
37+
ShowUsage;
38+
end;
39+
Result.Add(Value);
40+
end;
41+
end;
42+
43+
44+
function FormatIntegerList(const List: TIntegerList): string;
45+
var
46+
i: integer;
47+
Builder: TStringBuilder;
48+
begin
49+
Builder := TStringBuilder.Create;
50+
try
51+
for i := 0 to List.Count - 1 do
52+
begin
53+
if i > 0 then
54+
Builder.Append(', ');
55+
Builder.Append(IntToStr(List[i]));
56+
end;
57+
Result := Builder.ToString;
58+
finally
59+
Builder.Free;
60+
end;
61+
end;
62+
63+
function LongestCommonSubsequence(const A, B: TIntegerList): TIntegerList;
64+
var
65+
PreviousRow, CurrentRow: array of integer;
66+
i, j: integer;
67+
begin
68+
if B.Count > A.Count then
69+
Exit(LongestCommonSubsequence(B, A));
70+
71+
SetLength(PreviousRow, B.Count + 1);
72+
SetLength(CurrentRow, B.Count + 1);
73+
74+
// Build the DP table
75+
for i := 1 to A.Count do
76+
begin
77+
for j := 1 to B.Count do
78+
if A[i - 1] = B[j - 1] then
79+
CurrentRow[j] := PreviousRow[j - 1] + 1
80+
else
81+
if CurrentRow[j - 1] > PreviousRow[j] then
82+
CurrentRow[j] := CurrentRow[j - 1]
83+
else
84+
CurrentRow[j] := PreviousRow[j];
85+
86+
PreviousRow := CurrentRow;
87+
SetLength(CurrentRow, B.Count + 1);
88+
end;
89+
90+
// Reconstruct the LCS from the DP table
91+
Result := TIntegerList.Create;
92+
i := A.Count;
93+
j := B.Count;
94+
95+
while (i > 0) and (j > 0) do
96+
if A[i - 1] = B[j - 1] then
97+
begin
98+
// If they match, append
99+
Result.Add(A[i - 1]);
100+
Dec(i);
101+
Dec(j);
102+
end
103+
else if PreviousRow[j] > CurrentRow[j - 1] then
104+
// Move up if the top cell has a greater value
105+
Dec(i)
106+
else
107+
// Move left if the left cell has a greater value
108+
Dec(j);
109+
110+
Result.Reverse;
111+
end;
112+
113+
114+
var
115+
ListA, ListB, LCSResult: TIntegerList;
116+
i: integer;
117+
begin
118+
if ParamCount <> 2 then
119+
ShowUsage;
120+
121+
try
122+
try
123+
ListA := ParseIntegerList(ParamStr(1));
124+
ListB := ParseIntegerList(ParamStr(2));
125+
126+
if (ListA.Count = 0) or (ListB.Count = 0) then
127+
ShowUsage;
128+
129+
LCSResult := LongestCommonSubsequence(ListA, ListB);
130+
131+
if LCSResult.Count = 0 then
132+
Writeln('No common subsequence.')
133+
else
134+
Writeln(FormatIntegerList(LCSResult));
135+
except
136+
on E: Exception do
137+
ShowUsage;
138+
end;
139+
finally
140+
ListA.Free;
141+
ListB.Free;
142+
LCSResult.Free;
143+
end;
144+
end.

0 commit comments

Comments
 (0)