【问题标题】:Find longest non-decreasing sequence查找最长的非递减序列
【发布时间】:2011-01-24 22:10:53
【问题描述】:

鉴于以下问题,

给定一个长度为 n 的整数数组 A,找出最长的序列 {i_1, ..., i_k} 使得 i_j

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

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

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

有人可以帮忙吗?

谢谢

【问题讨论】:

  • 对我来说看起来不错。你能解释一下为什么你认为它不正确吗?

标签: algorithm


【解决方案1】:

我在您的算法中看不到任何回溯,它似乎适合连续的非递减数字块。如果我理解正确,请输入以下内容:

1 2 3 4 10 5 6 7

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

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

【讨论】:

  • 我想这就是我要找的。正如您所提到的,最初的问题并没有强调序列应该是连续的。 -thx
【解决方案2】:

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

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

除非您的条件被破坏,否则您永远不会将try_starttry_end 提升为max_startmax_end。您需要在循环结束时执行相同的检查。

【讨论】:

  • 我认为这是相同的评论,但是对于长度为 1 的列表,这不会通过循环运行,因此您会得到 0 和 0 的开始和结束
  • 我已根据您的建议对我的解决方案进行了更正。但是,我担心的是,考虑到原始问题,我的解决方案从根本上是错误的,因为书中提供的解决方案使用了一个相当复杂的 DP 来解决它。我想我错过了这个问题的一些关键信息。 -thx
【解决方案3】:

嗯,看起来您正在寻找序列的开始和结束,这可能是正确的,但不是所要求的。我将从阅读http://en.wikipedia.org/wiki/Longest_increasing_subsequence 开始 - 我相信这是被问到的问题,这是一个相当知名的问题。通常不能在线性时间内求解,并且还需要某种形式的动态规划。 (维基百科上也有一个更简单的 n^2 算法变体 - 只需进行线性扫描而不是二进制搜索。)

【讨论】:

    【解决方案4】:
    #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;
    }
    

    【讨论】:

    • 请解释一下你的代码,而不是像这样发布它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2016-04-11
    • 2011-06-23
    相关资源
    最近更新 更多