2012-03-20 23 views
5

Một chuỗi trong đó giá trị của các phần tử đầu tiên giảm và sau đó tăng được gọi là V-Trình tự. Trong một V-Sequence hợp lệ, cần có ít nhất một phần tử trong phần tử giảm dần và ít nhất một phần tử trong nhánh tăng. Ví dụ: "5 3 1 9 17 23" là một chuỗi V hợp lệ có hai phần tử trong nhánh giảm là 5 và 3 và 3 phần tử trong nhánh tăng là 9, 17 và 23. Nhưng không có chuỗi nào "6 4 2" hoặc "8 10 15" là V-Sequence vì "6 4 2" không có phần tử nào trong phần tăng lên trong khi "8 10 15" không có phần tử trong phần giảm.tăng trình tự giảm dần

Cho một dãy số N tìm chuỗi con dài nhất (không nhất thiết tiếp giáp) của nó là một chuỗi V-Sequence?

Có thể thực hiện điều này trong O (n)/O (logn)/O (n^2) không?

+0

Những con số trong dãy là theo thứ tự giống như họ đang có trong chuỗi gốc, nhưng không cần phải tiếp giáp, phải không? – gcbenison

+0

có chính xác. Điều đó có nghĩa là bạn có thể xóa các phần tử khỏi chuỗi gốc nhưng không thể thêm và số lần xóa phải tối thiểu. –

+0

Bản sao của http://stackoverflow.com/questions/9764512/longest-subsequence-that-first-increases-then-decreases/9764580#9764580 –

Trả lời

4

Giải pháp khá giống với giải pháp của chuỗi dài nhất không giảm. Sự khác biệt là bây giờ cho mỗi phần tử bạn cần lưu trữ hai giá trị - chiều dài của chuỗi V dài nhất bắt đầu từ phần tử này và độ dài của chuỗi giảm dài nhất bắt đầu từ điều này là bao nhiêu. Xin hãy xem giải pháp của giải pháp typical non-decreasing subsequence và tôi tin rằng đây là một mẹo đủ tốt. Tôi tin rằng sự phức tạp tốt nhất mà bạn có thể đạt được là O (n * log (n)), nhưng một giải pháp phức tạp O (n^2) là dễ dàng hơn để đạt được.

Hy vọng điều này sẽ hữu ích.

0

Dưới đây là triển khai bằng Python dựa trên gợi ý rất hữu ích của izomorphius ở trên. Điều này được xây dựng trên this implementation của sự cố tăng dần. Nó hoạt động bởi, như izomorphius nói, theo dõi "những gì tốt nhất V được tìm thấy cho đến nay" cũng như "các chuỗi tăng tốt nhất được tìm thấy cho đến nay". Lưu ý rằng việc mở rộng V, một khi nó đã được xác định, không khác với việc mở rộng chuỗi giảm dần. Cũng phải có một quy tắc để "đẻ trứng" ứng viên mới của V từ các chuỗi tăng ngày trước đó.

from bisect import bisect_left 

def Vsequence(seq): 
    """Returns the longest (non-contiguous) subsequence of seq that 
    first increases, then decreases (i.e. a "V sequence"). 

    """ 
    # head[j] = index in 'seq' of the final member of the best increasing 
    # subsequence of length 'j + 1' yet found 
    head = [0] 
    # head_v[j] = index in 'seq' of the final member of the best 
    # V-subsequence yet found 
    head_v = [] 
    # predecessor[j] = linked list of indices of best increasing subsequence 
    # ending at seq[j], in reverse order 
    predecessor = [-1] * len(seq) 
    # similarly, for the best V-subsequence 
    predecessor_v = [-1] * len(seq) 
    for i in xrange(1, len(seq)): 

     ## First: extend existing V's via decreasing sequence algorithm. 
     ## Note heads of candidate V's are stored in head_v and that 
     ## seq[head_v[]] is a non-increasing sequence 
     j = -1 ## "length of best new V formed by modification, -1" 
     if len(head_v) > 0: 
      j = bisect_left([-seq[head_v[idx]] for idx in xrange(len(head_v))], -seq[i]) 

      if j == len(head_v): 
       head_v.append(i) 
      if seq[i] > seq[head_v[j]]: 
       head_v[j] = i 

     ## Second: detect "new V's" if the next point is lower than the head of the 
     ## current best increasing sequence. 
     k = -1 ## "length of best new V formed by spawning, -1" 
     if len(head) > 1 and seq[i] < seq[head[-1]]: 
      k = len(head) 

      extend_with(head_v, i, k + 1) 

      for idx in range(k,-1,-1): 
       if seq[head_v[idx]] > seq[i]: break 
       head_v[idx] = i 

     ## trace new predecessor path, if found 
     if k > j: 
      ## It's better to build from an increasing sequence 
      predecessor_v[i] = head[-1] 
      trace_idx = predecessor_v[i] 
      while trace_idx > -1: 
       predecessor_v[trace_idx] = predecessor[trace_idx] 
       trace_idx=predecessor_v[trace_idx] 
     elif j > 0: 
      ## It's better to extend an existing V 
      predecessor_v[i] = head_v[j - 1] 

     ## Find j such that: seq[head[j - 1]] < seq[i] <= seq[head[j]] 
     ## seq[head[j]] is increasing, so use binary search. 
     j = bisect_left([seq[head[idx]] for idx in xrange(len(head))], seq[i]) 

     if j == len(head): 
      head.append(i) ## no way to turn any increasing seq into a V! 
     if seq[i] < seq[head[j]]: 
      head[j] = i 

     if j > 0: predecessor[i] = head[j - 1] 

    ## trace subsequence back to output 
    result = [] 
    trace_idx = head_v[-1] 
    while (trace_idx >= 0): 
     result.append(seq[trace_idx]) 
     trace_idx = predecessor_v[trace_idx] 

    return result[::-1] 

Một số ví dụ đầu ra:

>>> l1 
[26, 92, 36, 61, 91, 93, 98, 58, 75, 48, 8, 10, 58, 7, 95] 
>>> Vsequence(l1) 
[26, 36, 61, 91, 93, 98, 75, 48, 10, 7] 
>>> 
>>> l2 
[20, 66, 53, 4, 52, 30, 21, 67, 16, 48, 99, 90, 30, 85, 34, 60, 15, 30, 61, 4] 
>>> Vsequence(l2) 
[4, 16, 48, 99, 90, 85, 60, 30, 4]