2011-01-24 17 views
5

Data la seguente domanda,Trova più lunga sequenza non decrescente

dato un array di interi A di lunghezza n, trovare la sequenza più lunga {I_1, ..., i_k} tale che i_j < i_ (j + 1) e A [i_j] < = A [i_ (j + 1)] per qualsiasi j in [1, k-1].

Ecco la mia soluzione, è corretta?

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 

In qualche modo, non credo che questa è una soluzione corretta, ma non riesco a trovare un contro-esempio che disapprovano questa soluzione.

chiunque può aiutare?

Grazie

+1

Mi sembra abbastanza buono. Puoi dare qualche idea del perché pensi che sia scorretto? –

risposta

5

Non vedo alcun backtracking nell'algoritmo e sembra adatto per blocchi contigui di numeri non decrescenti. Se ho capito bene, per il seguente testo:

1 2 3 4 10 5 6 7 

vostro algoritmo sarebbe tornato 1 2 3 4 10 invece di 1 2 3 4 5 6 7.

Provare a trovare una soluzione utilizzando dynamic programming.

+0

Penso che questo sia quello che sto cercando. Come hai detto, la domanda originale non sottolinea che la sequenza dovrebbe essere continua. -thx – q0987

2

Stai perdendo il caso in cui la condizione non è rotto nella sua ultima iterazione:

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

Non sarai mai promuovere try_start e try_end-max_start e max_end a meno che la sua condizione è rotto. È necessario eseguire lo stesso controllo alla fine del ciclo.

+0

Penso che sia lo stesso commento, ma per un elenco di lunghezza 1, questo non viene eseguito attraverso il ciclo in modo da ottenere 0 e 0 per l'inizio e la fine – vmpstr

+0

Ho effettuato una correzione per la mia soluzione in base al tuo suggerimento. Tuttavia, la mia preoccupazione è che la mia soluzione sia fondamentalmente errata data la domanda originale perché la soluzione fornita dal libro utilizza un DP abbastanza complicato per risolverlo. Penso di perdere alcune informazioni chiave dalla domanda. -thx – q0987

+0

ah - Ho perso l'aspetto di contiguità. in bocca al lupo! –

1

Bene, sembra che tu stia trovando l'inizio e la fine della sequenza, che potrebbe essere corretta ma non è stato quello che è stato chiesto. Vorrei iniziare leggendo http://en.wikipedia.org/wiki/Longest_increasing_subsequence - Credo che questa sia la domanda che è stata posta ed è un problema abbastanza noto. In generale non può essere risolto in tempo lineare e richiederà anche qualche forma di programmazione dinamica. (C'è anche una variante n^2 più semplice dell'algoritmo su Wikipedia - basta fare uno sweep lineare invece della ricerca binaria.)

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

Spiega il tuo codice piuttosto che pubblicarlo esattamente come questo. –

Problemi correlati