#include <cassert>
#include <string>
#include <vector>

class Solution {
    auto dp_helper(const std::string &t1, const std::string &t2,
                   std::vector<int> &dp, int i, int j) -> int {
        if (i < 0 || j < 0) {
            return 0;
        }

        auto idx = i * t2.size() + j;
        if (dp[idx] != -1) {
            return dp[idx];
        }

        if (t1[i] == t2[j]) {
            dp[idx] = 1 + dp_helper(t1, t2, dp, i - 1, j - 1);
        } else {
            dp[idx] = std::max(dp_helper(t1, t2, dp, i - 1, j),
                               dp_helper(t1, t2, dp, i, j - 1));
        }

        return dp[idx];
    }

  public:
    auto longestCommonSubsequence(const std::string &text1,
                                  const std::string &text2) -> int {
        int m = text1.size();
        int n = text2.size();
        std::vector<int> dp(m * n, -1);
        return dp_helper(text1, text2, dp, m - 1, n - 1);
    }
};

int main() {
    Solution s;

    assert(s.longestCommonSubsequence("abcde", "ace") == 3);
    assert(s.longestCommonSubsequence("abc", "abc") == 3);
    assert(s.longestCommonSubsequence("abc", "def") == 0);

    return 0;
}