找到最长的非递减序列

时间:2011-01-24 22:10:53

标签: algorithm

鉴于以下问题,

给定长度为n的整数A的数组,找到最长的序列{i_1,...,i_k},使得i_j&lt;对于[1,k-1]中的任何j,i_(j + 1)和A [i_j] <= A [i_(j + 1)]。

这是我的解决方案,这是正确的吗?

max_start = 0; // store the final result
max_end   = 0;
try_start = 0; // store the initial result
try_end   = 0;

FOR i=0; i<(A.length-1); i++ DO
  if A[i] <= A[i+1]
     try_end = i+1; // satisfy the condition so move the ending point
  else              // now the condition is broken
     if (try_end - try_start) > (max_end - max_start) // keep it if it is the maximum
        max_end   = try_end;
        max_start = try_start;
     endif
     try_start = i+1; // reset the search
     try_end   = i+1;
  endif
ENDFOR

// Checking the boundary conditions based on comments by Jason
if (try_end - try_start) > (max_end - max_start) 
   max_end   = try_end;
   max_start = try_start;
endif

不知何故,我不认为这是一个正确的解决方案,但我找不到反对这个解决方案的反例。

任何人都可以提供帮助吗?

谢谢

4 个答案:

答案 0 :(得分:5)

我没有看到你的算法有任何回溯,它似乎适用于非递减数字的连续块。如果我理解正确,请输入以下内容:

1 2 3 4 10 5 6 7

您的算法将返回1 2 3 4 10而不是1 2 3 4 5 6 7

尝试使用dynamic programming找到解决方案。

答案 1 :(得分:2)

你错过了最后一次迭代没有破坏条件的情况:

1, 3, 5, 2, 4, 6, 8, 10

除非您的情况被破坏,否则您永远不会将try_starttry_end宣传给max_startmax_end。您需要在循环结束时执行相同的检查。

答案 2 :(得分:1)

好吧,看起来你正在找到序列的开始和结束,这可能是正确的,但它不是被问到的。我从阅读http://en.wikipedia.org/wiki/Longest_increasing_subsequence开始 - 我相信这是被问到的问题,这是一个相当众所周知的问题。一般不能在线性时间内解决,也需要某种形式的动态编程。 (维基百科上的算法也有一个更简单的n ^ 2变体 - 只需进行线性扫描而不是二分搜索。)

答案 3 :(得分:-1)

#include <algorithm>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <assert.h>

template<class RandIter>
class CompM {
    const RandIter X;
    typedef typename std::iterator_traits<RandIter>::value_type value_type;
    struct elem {
        value_type c; // char type
        explicit elem(value_type c) : c(c) {}
    };
public:
    elem operator()(value_type   c) const { return elem(c); }
    bool operator()(int  a, int  b) const { return X[a]  < X[b];  } // for is_sorted
    bool operator()(int  a, elem b) const { return X[a]  <   b.c; } // for find
    bool operator()(elem a, int  b) const { return   a.c < X[b];  } // for find
    explicit CompM(const RandIter X) : X(X) {}
};

template<class RandContainer, class Key, class Compare>
int upper(const RandContainer& a, int n, const Key& k, const Compare& comp) {
    return std::upper_bound(a.begin(), a.begin() + n, k, comp) - a.begin();
}

template<class RandIter>
std::pair<int,int> lis2(RandIter X, std::vector<int>& P)
{
    int n = P.size(); assert(n > 0);
    std::vector<int> M(n);
    CompM<RandIter> comp(X);
    int L = 0;
    for (int i = 0; i < n; ++i) {
        int j = upper(M, L, comp(X[i]), comp);
        P[i] = (j > 0) ? M[j-1] : -1;
        if (j == L) L++;
        M[j] = i;
    }
    return std::pair<int,int>(L, M[L-1]);
}

int main(int argc, char** argv)
{
    if (argc < 2) {
        fprintf(stderr, "usage: %s string\n", argv[0]);
        return 3;
    }
    const char* X = argv[1];
    int n = strlen(X);
    if (n == 0) {
        fprintf(stderr, "param string must not empty\n");
        return 3;
    }
    std::vector<int> P(n), S(n), F(n);
    std::pair<int,int> lt = lis2(X, P); // L and tail
    int L = lt.first;
    printf("Longest_increasing_subsequence:L=%d\n", L);
    for (int i = lt.second; i >= 0; --i) {
        if (!F[i]) {
            int j, k = 0;
            for (j = i; j != -1; j = P[j], ++k) {
                S[k] = j;
                F[j] = 1;
            }
            std::reverse(S.begin(), S.begin()+k);
            for (j = 0; j < k; ++j)
                printf("%c", X[S[j]]);
            printf("\n");
        }
    }
    return 0;
}