0

Why my c++ implementation for finding Longest Common Subsequence gives time limit error on LeetCode. How can I improve the time complexity of this algorithm?

    int longestCommonSubsequence(string text1, string text2) {
        int n1 = text1.length(), n2 = text2.length();
        vector<vector<int>> dp(n1+1, vector<int>(n2+1, -1));
        longestCommonSubsequence(text1, text2, n1, n2, dp);
        return dp[n1][n2];
    }
    int longestCommonSubsequence(string text1, string text2, int n1, int n2, 
                                  vector<vector<int>> &dp) {
        if(n1==0 || n2==0) {
            return 0;
        }
        
        if(dp[n1][n2] != -1) {
            return dp[n1][n2];
        }
        
        if(text1[n1-1]==text2[n2-1]) {
            dp[n1][n2] = 1 + longestCommonSubsequence(text1, text2, n1-1, n2-1, dp);
            return dp[n1][n2];
        }
        else {
            dp[n1][n2] = max(longestCommonSubsequence(text1, text2, n1-1, n2, dp), 
                       longestCommonSubsequence(text1, text2, n1, n2-1, dp));
            return dp[n1][n2];
        }
    }
2
  • 3
    Don't know if it matters, but you could pass text1 and text2 by const reference instead of by value Commented Sep 10, 2020 at 6:18
  • Do you really need to allocate a matrix of (n1+1)x(n2+1)? Wouldn't n1xn2 suffice? Also, I wonder if it would help starting on n1/2, searching for a logarithmic complexity instead of linear. It may be worth a think, if that goes well along with memoization. Commented Sep 10, 2020 at 9:32

2 Answers 2

1

We can solve the problem without recursion, similarly using dynamic programming. This'd pass without TLE:

// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    return 0;
}();

// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
#include <vector>
#include <algorithm>

using ValueType = std::uint_fast16_t;

static const struct Solution {
    static const int longestCommonSubsequence(
        const std::string& text_a,
        const std::string& text_b
    ) {
        const ValueType a_len = std::size(text_a);
        const ValueType b_len = std::size(text_b);
        std::vector<std::vector<ValueType>> dp(a_len + 1, std::vector<ValueType>(b_len + 1));

        for (ValueType a = 1; a <= a_len; ++a) {
            for (ValueType b = 1; b <= b_len; ++b) {
                if (text_a[a - 1] == text_b[b - 1]) {
                    dp[a][b] = 1 + dp[a - 1][b - 1];

                } else {
                    dp[a][b] = std::max(dp[a - 1][b], dp[a][b - 1]);
                }
            }
        }

        return dp[a_len][b_len];
    }
};
Sign up to request clarification or add additional context in comments.

Comments

0

Send text1 and text2 as a reference because if we pass it by value, for each recursion call a copy of the string is created, which is additional O(string_length) overhead for each recursion call.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.