hieuza

Longest Increasing Subsequence, O(n log(n))

Oct 21st, 2012
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.24 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # @ hieuza [x] gmail.com
  3.  
  4. # longest increasing sequence
  5. # O(n log n) algorithm
  6. # http://en.wikipedia.org/wiki/Longest_increasing_subsequence
  7.  
  8. def simple_search(s, i, m, p, L):
  9.     # simple linear search
  10.     for j in xrange(L, 0, -1):
  11.         if s[m[j]] < s[i]:
  12.             return j
  13.     return 0
  14.  
  15.  
  16. # binary search
  17. # search for *max* j in lo..hi, s.t., s[m[j]] < s[i]
  18. def binary_search(s, i, m, p, lo, hi):
  19.     if s[m[hi]] < s[i]:
  20.         return hi
  21.  
  22.     if lo > hi:
  23.         return 0 # not found
  24.  
  25.     mid = lo + (hi - lo)/2
  26.     if s[m[mid]] < s[i]:
  27.         return binary_search(s, i, m, p, mid, hi - 1)
  28.     else:
  29.         return binary_search(s, i, m, p, lo, mid - 1)
  30.  
  31.  
  32. def search(s, i, m, p, L):
  33.     return binary_search(s, i, m, p, 1, L)
  34.  
  35.  
  36. def extract_lis(s, m, p, L):
  37.     lis = []
  38.     x = m[L]
  39.     for _ in xrange(L, 0, -1):
  40.         lis = [s[x]] + lis
  41.         x = p[x]
  42.    
  43.     return lis
  44.  
  45.  
  46. def lis(s):
  47.     n = len(s)
  48.  
  49.     # for an increasing sequence of length j,
  50.     # m[j] = k is the position of the smallest value s[k]
  51.     # that is end of the sequence of length j.
  52.     # so s[m[1]], s[m[2]], ... s[m[L]] is the longest sequence.
  53.     m = [-1]*(n + 1)
  54.  
  55.     # p[i] is the position of the predecessor of s[i] in an increasing sequence.
  56.     # need to use p[i] in binary search
  57.     p = [0]*n
  58.  
  59.     # current max length
  60.     L = 0
  61.  
  62.     for i, si in enumerate(s):
  63.         # search for maximum j, s.t., s[m[j]] < s[i]
  64.         # i.e., j is the max length of an i.s that has end value less than s[i]
  65.         j = search(s, i, m, p, L)
  66.  
  67.         # parrent of i
  68.         p[i] = m[j]
  69.  
  70.         if j == L or s[m[j + 1]] > s[i]:
  71.             # update the end of sequence of length j + 1 to be i
  72.             # it can happen when j == L, i.e., x[i] extends the current longest i.s
  73.             # OR, x[i] is a new end of an existing i.s. of length j + 1
  74.             m[j + 1] = i
  75.  
  76.             L = max(L, j + 1)
  77.  
  78.     # only print small list
  79.     if n <= 30:
  80.         print 's:', s
  81.         print 'm:', m
  82.         print 'p:', p
  83.         lis = extract_lis(s, m, p, L)
  84.         print 'lis:', lis
  85.  
  86.     print 'max LIS length:', L
  87.  
  88.  
  89. def test(n, vmax):
  90.     import random
  91.     # s = [1, 2, 1]
  92.     s = [random.randint(1, vmax) for _ in xrange(n)]
  93.     lis(s)
  94.  
  95.  
  96. if __name__ == '__main__':
  97.     import sys
  98.  
  99.     n = 10
  100.     vmax = 20
  101.  
  102.     print 'usage: [n] [vmax]'
  103.  
  104.     if len(sys.argv) > 1:
  105.         n = int(sys.argv[1])
  106.    
  107.     if len(sys.argv) > 2:
  108.         vmax = int(sys.argv[2])
  109.  
  110.     test(n, vmax)
Advertisement
Add Comment
Please, Sign In to add comment