Repository: vaskoz/dailycodingproblem-go (go)

Issue:
Day 396
Good morning! Here's your coding interview problem for today.

This problem was asked by Google.

Given a string, return the length of the longest palindromic subsequence in the string.

For example, given the following string:

`MAPTPTMTPA`
Return `7`, since the longest palindromic subsequence in the string is `APTMTPA`. Recall that a subsequence of a string does not have to be contiguous!

Your algorithm should run in O(n^2) time and space.

Pull request:
Day396
Resolves #795.

Patch:
diff --git a/README.md b/README.md
index 5b3d870..3fe325e 100644
--- a/README.md
+++ b/README.md
@@ -388,4 +388,5 @@ problems from
 * [Day 393](https://github.com/vaskoz/dailycodingproblem-go/issues/789)
 * [Day 394](https://github.com/vaskoz/dailycodingproblem-go/issues/791)
 * [Day 395](https://github.com/vaskoz/dailycodingproblem-go/issues/793)
+* [Day 396](https://github.com/vaskoz/dailycodingproblem-go/issues/795)
 
diff --git a/day396/problem.go b/day396/problem.go
new file mode 100644
index 0000000..3e8bdb6
--- /dev/null
+++ b/day396/problem.go
@@ -0,0 +1,67 @@
+package day396
+
+// LongestPalindromicSubsequenceBrute returns the Longest
+// Palindromic Subsequence using brute force.
+func LongestPalindromicSubsequenceBrute(str string) int {
+	runes := []rune(str)
+
+	return lpsBrute(runes)
+}
+
+func lpsBrute(r []rune) int {
+	switch l := len(r); {
+	case l == 1:
+		return 1
+	case l == 2 && r[0] == r[1]:
+		return 2
+	case r[0] == r[l-1]:
+		return lpsBrute(r[1:l-1]) + 2
+	default:
+		return max(
+			lpsBrute(r[:l-1]),
+			lpsBrute(r[1:l]),
+		)
+	}
+}
+
+func max(a, b int) int {
+	if a > b {
+		return a
+	}
+
+	return b
+}
+
+// LongestPalindromicSubsequenceDP returns the Longest
+// Palindromic Subsequence using Dynamic Programming.
+// Runs in O(N^2) space and time.
+func LongestPalindromicSubsequenceDP(str string) int {
+	runes := []rune(str)
+
+	return lpsDP(runes)
+}
+
+func lpsDP(r []rune) int {
+	n := len(r)
+	subprob := make([][]int, n)
+
+	for i := range subprob {
+		subprob[i] = make([]int, n)
+		subprob[i][i] = 1
+	}
+
+	for length := 2; length <= n; length++ {
+		for i := 0; i <= n-length; i++ {
+			switch j := i + length - 1; {
+			case r[i] == r[j] && length == 2:
+				subprob[i][j] = 2
+			case r[i] == r[j]:
+				subprob[i][j] = subprob[i+1][j-1] + 2
+			default:
+				subprob[i][j] = max(subprob[i][j-1], subprob[i+1][j])
+			}
+		}
+	}
+
+	return subprob[0][n-1]
+}


Test patch:
diff --git a/day396/problem_test.go b/day396/problem_test.go
new file mode 100644
index 0000000..8ca7992
--- /dev/null
+++ b/day396/problem_test.go
@@ -0,0 +1,48 @@
+package day396
+
+import "testing"
+
+// nolint
+var testcases = []struct {
+	str      string
+	expected int
+}{
+	{"MAPTPTMTPA", 7},
+	{"ABFOOBARRABOOFYZ", 12},
+}
+
+func TestLongestPalindromicSubsequenceBrute(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range testcases {
+		if res := LongestPalindromicSubsequenceBrute(tc.str); res != tc.expected {
+			t.Errorf("Expected %v, got %v", tc.expected, res)
+		}
+	}
+}
+
+func BenchmarkLongestPalindromicSubsequenceBrute(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			LongestPalindromicSubsequenceBrute(tc.str)
+		}
+	}
+}
+
+func TestLongestPalindromicSubsequenceDP(t *testing.T) {
+	t.Parallel()
+
+	for _, tc := range testcases {
+		if res := LongestPalindromicSubsequenceDP(tc.str); res != tc.expected {
+			t.Errorf("Expected %v, got %v", tc.expected, res)
+		}
+	}
+}
+
+func BenchmarkLongestPalindromicSubsequenceDP(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			LongestPalindromicSubsequenceDP(tc.str)
+		}
+	}
+}