Calculating LIS (Longest Increasing Subsequence) in an array is a very famous Dynamic Programming problem. However in every tutorial they first show the recursive solution without using the concepts of DP and then solve it by applying Bottom-Up DP (Iterative Solution).
My question is:
How will we use Memoization in Recursive Solution itself. Not just Memoization but memoization using 1D array.
I did some research but could not find anything of relevance. Although there are 2 places where recursive memoization has been asked 1 & 2 but the solutions over there, are using 2D Map / Array for memoization.
Anyway Memoizing the solution with 1D array, is giving wrong output. Here is what I did:
int lis(int idx, int prev)
{
    if(idx >= N)
        return 0;
    if(dp[idx])
        return dp[idx];
    int best_ans = lis(idx+1, prev);
    int cur_ans = 0;
    if(arr[idx] > prev)
    {
        cur_ans = 1 + lis(idx+1, arr[idx]);
    }
    int ans = max(best_ans, cur_ans);
    dp[idx] = ans;
    return ans;
}
int main()
{
    // Scan N 
    // Scan arr
    ans = lis(0, -1));
    print ans;
}
Although I know the reason why this solution is giving Wrong output as:
There can be more than one solution for the giving index based on what was the previous value.
But I still want to know how it can be done using 1D array.
I am curious to know the solution because I have read that every DP Top-Down solution can be reframed into Bottom-Up and vice-versa.
It would be highly helpful if someone could provide some insight for the same.
Thanks in advance.
This can't be done because the problem fundamentally needs a 2D data structure to solve.
The bottom-up approach can cheat by producing one row at a time of the data structure. Viewed over time, it produces a 2D data structure, but at any given time you only see one dimension of it.
The top-down approach has to build the entire 2D data structure.
This is a fundamental tradeoff in DP. It is usually easier to write down the top-down approach. But the bottom-up approach only has to have part of the overall data structure at any time, and therefore has significantly lower memory requirements.
def LongestIncreasingSubsequenceMemo(nums, i, cache):
    if cache[i] > 0:
        return cache[i]
    result = 1
    for j in range(i):
        if nums[i] > nums[j]:
            result = max(result, 1 + LongestIncreasingSubsequenceMemo(nums, j, cache))
    cache[i] = result
    return result
def main():
    nums = [1,2,3,4,5]
    if not nums:
        return 0        
    n = len(nums)
    cache = [0 for i in range(n)]
    result = 1
    for i in range(n):
        result = max(result, LongestIncreasingSubsequenceMemo(nums, i, cache))
    return result
if __name__ == "__main__":
    print(main())
In the above solution, we are taking a one-dimensional array and updating it for each element in the array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With