简体   繁体   中英

longest increasing subsequence wrong answer

I wrote a recursive solution for the longest increasing subsequence and it worked perfectly fine. But when I applied dp on the same code it gives different answers. Problem Link: https://practice.geeksforgeeks.org/problems/longest-increasing-subsequence-1587115620/1 Recursive code:

int LISrecursive(int arr[], int n, int currIndex, int maxVal) {
    if (currIndex == n) {
        return 0;
    }
    int included = 0, notIncluded = 0;
    if (arr[currIndex] > maxVal) {
        included = 1 + LISrecursive(arr, n, currIndex + 1, arr[currIndex]);
    }
    notIncluded = LISrecursive(arr, n, currIndex + 1, maxVal);

    return max(notIncluded, included);

}

DP Code:

int LISdp(int arr[], int n, int currIndex, int maxVal, vector<int> &dp) {
    if (currIndex == n) {
        return 0;
    }
    if (dp[currIndex] != -1) return dp[currIndex];
    int included = 0, notIncluded = 0;
    if (arr[currIndex] > maxVal) {
        included = 1 + LISdp(arr, n, currIndex + 1, arr[currIndex], dp);
    }
    notIncluded = LISdp(arr, n, currIndex + 1, maxVal, dp);

    return dp[currIndex] = max(notIncluded, included);

}
int32_t main() {
    int n;
    cin >> n;
    int arr[n];
    vector<int> dp(n, -1);
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    cout << LISrecursive(arr,n,0,-1); 
    cout << LISdp(arr, n, 0 , -1, dp);
    return 0;
}

I cannot figure out what I did wrong? For this test case 6 (n) 6 3 7 4 6 9 (arr[]) Recursive code gives 4 answer(correct) But DP code gives 3 answer(incorrect)

When I think of dynamic programming, I usually break it down into two steps:

  1. Solve the recursion with "including the current element before recursing again" compared to "not including the current element before recursing again". This is exactly what you did with your recursive solution.

  2. Take the recursive solution from step 1 and add a cache of previous computed results to avoid repetitive recursion. The cache, can be conceptualized as a multidimension matrix that maps all the non-const variable parameters passed to the recursive function to the final result.

In your case, each recursive step has two variables, currIndex , and maxVal . a and n are actually constants throughout the entire recursion. The number of non-const parameters of the recursive step is the number of dimensions in your cache . So you need a two dimensional table. We could use a big 2-d int array, but that would take a lot of memory. We can achieve the same efficiency with a nested pair of hash tables.

Your primary mistake is that your cache is only 1 dimension - caching the result compared to currIndex irrespective of the value of maxVal . The other mistake is using a vector instead of a hash table. The vector technique you have works, but doesn't scale. And when we add a second dimension, the scale in terms of memory use are even worse.

So let's defined a cache type as an unordered_map (hash table) that maps currIndex to another hash table that maps maxVal to the result of the recursion. You could also use tuples, but the geeksforgeeks coding site doesn't seem to like that. No bother, we can just define this:

typedef std::unordered_map<int, std::unordered_map<int, int>> CACHE;

Then your DP solution is effectively just inserting a lookup into the CACHE at the top of the recursive function and an insertion into the CACHE at the bottom of the function.

int LISdp(int arr[], int n, int currIndex, int maxVal, CACHE& cache) {
    if (currIndex == n) {
        return 0;
    }

    // check our cache if we've already solved for currIndex and maxVal together
    auto itor1 = cache.find(currIndex);
    if (itor1 != cache.end())
    {
        // itor1->second is a reference to cache[currIndex]
        auto itor2 = itor1->second.find(maxVal);
        if (itor2 != itor1->second.end())
        {
            // itor2->second is a reference to cache[n][maxVal];
            return itor2->second;
        }
    }

    int included = 0, notIncluded = 0;
    if (arr[currIndex] > maxVal) {
        included = 1 + LISdp(arr, n, currIndex + 1, arr[currIndex], cache);
    }
    notIncluded = LISdp(arr, n, currIndex + 1, maxVal, cache);

    // cache the final result into the 2-d map before returning
    int finalresult = std::max(notIncluded, included);
    cache[currIndex][maxVal] = finalresult; // cache the result
    return finalresult;

}

Then the initial invocation with the input set to solve for is effectively passing INT_MIN as the intial maxVal and an empty cache:

int N = 16
int A[N]={0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};

CACHE cache;
int result = LISdp(A, N, 0, INT_MIN, cache);

A minor optimization is to make a , n , and cache a member variable of the C++ class encapsulating your solution so that they don't have to be pushed onto the stack for each step of the recursion. The cache is getting passed by reference, so it's not that big of a deal.

You have 2 problems in your code:

Mistake 1

First in C++, the size of an array must be a compile-time constant .So, take for example the following code snippets:

int n = 10;
int arr[n]; //INCORRECT because n is not a constant expression

The correct way to write the above would be:

const int n = 10;
int arr[n]; //CORRECT

Similarly, the following(which you did in your code example) is incorrect:

 int n;
 cin >> n;
 int arr[n];// INCORRECT because n is not a constant expression

Mistake 2

Second in your function LISdp , it seems to me that there is no need of the statement

if (dp[currIndex] != -1) return dp[currIndex];//no need for this statement

You should just remove this(the above) statement and the program produces expected output 4 as can be seen here . Basically you have not thought this(LISdp's working) through. You can use the debugger to see where you're going wrong.

There might be other problems in your code but so far i am able to spot these 2.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM