Implement a function to find the longest common decreasing subsequence (LDDS) between two sequences

problemsolving
Published

July 6, 2024

Finding the Longest Common Decreasing Subsequence (LDDS) in JavaScript

The Longest Common Decreasing Subsequence (LDDS) problem is a fascinating variation on the classic Longest Common Subsequence (LCS) problem. Instead of simply finding the longest common subsequence, we’re looking for the longest subsequence that’s also strictly decreasing. This adds a layer of complexity, requiring a more complex approach than a straightforward dynamic programming solution for LCS.

Let’s tackle this challenge in JavaScript. We’ll utilize dynamic programming, but our approach will need to account for the decreasing constraint. The key idea is to maintain a table that stores the length of the LDDS ending at each pair of indices in the input sequences.

Here’s a JavaScript function that implements this algorithm:

function longestCommonDecreasingSubsequence(arr1, arr2) {
  const m = arr1.length;
  const n = arr2.length;

  // Initialize a 2D array to store lengths of LDDS
  const dp = Array(m + 1).fill(0).map(() => Array(n + 1).fill(0));

  // Iterate through the arrays
  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (arr1[i - 1] === arr2[j - 1]) {
        //If elements are equal, find the length of LDDS ending at this point.
        let maxLength = 0;
        for (let k = 0; k < i; k++){
          for (let l = 0; l < j; l++){
            if(arr1[i-1] < arr1[k] && arr1[k] === arr2[l] && dp[k][l] > maxLength){
              maxLength = dp[k][l]
            }
          }
        }
        dp[i][j] = maxLength + 1;
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }

  // Find the maximum length in the DP table
  let maxLength = 0;
  for (let i = 0; i <= m; i++) {
    for (let j = 0; j <= n; j++) {
      maxLength = Math.max(maxLength, dp[i][j]);
    }
  }

  return maxLength;
}


// Example usage:
const arr1 = [3, 2, 1, 5, 4];
const arr2 = [5, 4, 3, 2, 1];
const ldssLength = longestCommonDecreasingSubsequence(arr1, arr2);
console.log("Length of LDDS:", ldssLength); // Output: 3 (e.g., 5, 4, 3 or 5, 4, 1 etc.)

const arr3 = [10, 22, 9, 33, 21, 50, 41, 60, 80];
const arr4 = [60, 80, 50, 41, 22, 10, 9, 21];

const ldssLength2 = longestCommonDecreasingSubsequence(arr3, arr4);
console.log("Length of LDDS:", ldssLength2); //Output: 4 (e.g., 60, 50, 22, 10)

This code efficiently finds the length of the LDDS. Further refinement could be added to reconstruct the actual LDDS sequence itself, rather than just its length, if needed. This would involve backtracking through the dp array. The time complexity of this solution is O(mnm*n), where ‘m’ and ‘n’ are the lengths of the input arrays. Optimizations are possible to reduce this complexity for certain input characteristics. However, the core logic remains the same: a dynamic programming approach tailored to handle the decreasing subsequence requirement. Note that this approach considers only strictly decreasing subsequences. If non-strictly decreasing subsequences are needed, a slight modification to the comparison within the nested loops would be required.