简体   繁体   English

最长递增和递减子序列(自上而下记忆)

[英]Longest Increasing and Decreasing subsequence (Top-Down with memoization)

Question - Given an array of integers, A of length N, find the length of longest subsequence which is first increasing then decreasing.问题 - 给定一个长度为 N 的整数数组 A,找出最长子序列的长度,它首先增加然后减少。 Input:[1, 11, 2, 10, 4, 5, 2, 1]输入:[1, 11, 2, 10, 4, 5, 2, 1]

Output: 6输出:6

Explanation:[1 2 10 4 2 1] is the longest subsequence.解释:[1 2 10 4 2 1] 是最长的子序列。

I wrote a top-down approach.我写了一个自顶向下的方法。 I have five arguments - vector A(containing the sequence), start index(denoting the current index), previous value, large(denoting maximum value in current subsequence) and map(m) STL.我有五个参数 - 向量 A(包含序列)、起始索引(表示当前索引)、先前值、大(表示当前子序列中的最大值)和 map(m) STL。

For the backtrack approach I have two cases -对于回溯方法,我有两种情况-

  1. element is excluded - In this case we move to next element(start+1).元素被排除 - 在这种情况下,我们移动到下一个元素(开始+1)。 prev and large remains same. prev 和 large 保持不变。

  2. element is included - having two cases包含元素 - 有两种情况

    a.一种。 if current value(A[start]) is greater than prev and prev == large then this is the case of increasing sequence.如果当前值(A[start]) 大于 prev 并且 prev == large 那么这就是递增序列的情况。 Then equation becomes 1 + LS(start+1, A[start], A[start]) ie prev becomes current element(A[start]) and largest element also becomes A[start].然后方程变为 1 + LS(start+1, A[start], A[start]) 即 prev 变为当前元素(A[start]),最大元素也变为 A[start]。

    b.if current value (A[start]) is lesser than prev and current (A[start]) < large then this is the case of decreasing sequence.如果当前值 (A[start]) 小于 prev 并且当前值 (A[start]) < 大,则这是递减序列的情况。 Then equation becomes 1 + LS(start+1, A[start], large) ie prev becomes current element(A[start]) and largest element remains same ie large.然后方程变为 1 + LS(start+1, A[start], large) 即 prev 变为当前元素(A[start]) 并且最大元素保持不变,即大。

Base Cases -基本案例 -

  1. if current index is out of the array ie start == end then return 0.如果当前索引不在数组中,即 start == end 然后返回 0。

  2. if sequence is decreasing and then increasing then return 0. ie if(current> previous and previous < maximum value) then return 0.如果序列减少然后增加则返回0。即如果(当前>前一个和前一个<最大值)则返回0。

This is not an optimized approach approach as map.find() is itself a costly operation.这不是一种优化方法,因为 map.find() 本身就是一个代价高昂的操作。 Can someone suggest optimized top-down approach with memoization.有人可以建议优化的自上而下的记忆方法。

int LS(const vector<int> &A, int start, int end, int prev, int large, map<string, int>&m){

    if(start == end){return 0;}
    if(A[start] > prev && prev < large){
        return 0;
    }

    string key = to_string(start) + '|' + to_string(prev) + '|' + to_string(large);

    if(m.find(key) == m.end()){
        int excl = LS(A, start+1, end, prev, large, m);
        int incl = 0;
        if(((A[start] > prev)&&(prev==large))){
            incl = 1 + LS(A, start+1, end, A[start],A[start], m); 
        }else if(((A[start]<prev)&&(A[start]<large))){
            incl = 1+ LS(A, start+1, end, A[start], large, m);
        }  

        m[key] = max(incl, excl);
    }

    return m[key];
}

int Solution::longestSubsequenceLength(const vector<int> &A) {
        map<string, int>m;
        return LS(A, 0, A.size(), INT_MIN, INT_MIN, m);
}

Not sure about top-down but it seems we could use the classic LIS algorithm to just approach each element from "both sides" as it were.不确定自上而下,但似乎我们可以使用经典的LIS算法从“双方”按原样接近每个元素。 Here's the example with each element as the rightmost and leftmost, respectively, as we iterate from both directions.这是我们从两个方向进行迭代时,每个元素分别位于最右侧和最左侧的示例。 We can see three instances of a valid sequence of length 6:我们可以看到长度为 6 的有效序列的三个实例:

[1, 11, 2, 10, 4, 5, 2, 1]

 1 11       11 10 4 2 1
 1 2                2 1
 1 2 10        10 4 2 1
 1 2 4            4 2 1
 1 2 4 5          5 2 1
 1 2                2 1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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