2011-01-24 104 views
5

鉴于以下问题,查找最长非递减序列

鉴于长度为n的一个整数数组,找到最长的序列{I_1,...,I_K}使得i_j < I_(J + 1 )和[1,k-1]中的任意j的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 

不知怎的,我不认为这是一个正确的解决方案,但我不能找到一个反例是不同意这种解决方案。

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

谢谢

+1

对我来说这看起来不错。你能否介绍一下为什么你认为这是不正确的? – 2011-01-24 22:13:42

回答

5

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

1 2 3 4 10 5 6 7 

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

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

2

你错过了在那里的条件并不在其最后一次迭代断线的情况:

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

你永远不会促进try_starttry_endmax_startmax_end除非你的条件是破碎。您需要在循环结束时执行相同的检查。

+0

我认为这是一个相同的评论,但对于长度为1的列表,这不通过循环,因此您得到0和0的开始和结束 – vmpstr 2011-01-24 22:18:51

+0

我根据您的建议对我的解决方案进行了更正。然而,我担心的是,鉴于原始问题,我的解决方案基本上是错误的,因为本书提供的解决方案使用相当复杂的DP来解决它。我想我错过了这个问题的一些关键信息。 -thx – q0987 2011-01-24 22:41:15

+0

啊 - 我错过了连续性方面。祝你好运! – 2011-01-25 03:14:00

1

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

-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; 
}