簡體   English   中英

如何正確記住這個 LIS python2.7 算法?

[英]How do I memoize this LIS python2.7 algorithm properly?

我正在練習動態規划,並且正在編寫最長遞增子序列問題。

我有DP解決方案:

def longest_subsequence(lst, lis=[], mem={}):
  if not lst:
    return lis
  if tuple(lst) not in mem.keys():
    if not lis or lst[0] > lis[-1]:
      mem[tuple(lst)] = max([longest_subsequence(lst[1:], lis+[lst[0]], mem), longest_subsequence(lst[1:], lis, mem)], key=len)
    else:
     mem[tuple(lst)] = longest_subsequence(lst[1:], lis, mem)
  return mem[tuple(lst)]

和一個非記憶版本

def longest_subsequence(lst, lis=[]):
  if not lst:
    return lis
  if not lis or lst[0] > lis[-1]:
    result = max([longest_subsequence(lst[1:], lis+[lst[0]]), longest_subsequence(lst[1:], lis)], key=len)
  else:
    result = longest_subsequence(lst[1:], lis)
  return result

但是,這兩個函數具有不同的行為。 例如,測試用例longest_subsequence([10,9,2,5,3,7,101,18])對於記憶版本失敗。

>>> longest_subsequence([10,9,2,5,3,7,101,18])
[10, 101]

然而,非記憶版本是完全正確的(雖然慢得多)。

>>> longest_subsequence([10,9,2,5,3,7,101,18])
[2, 5, 7, 101]

我做錯了什么?

你的狀態取決於兩個lst和您已選擇了一個項目。 但你只考慮lst 這就是為什么你得到不正確的結果。 要修復它,您只需將上一個項目添加到您的動態狀態。

def longest_subsequence(lst, prev=None, mem={}):
  if not lst:
    return []
  if (tuple(lst),prev) not in mem:
    if not prev or lst[0] > prev:
      mem[(tuple(lst),prev)] = max([[lst[0]]+longest_subsequence(lst[1:], lst[0]), longest_subsequence(lst[1:], prev)], key=len)
    else:
     mem[(tuple(lst),prev)] = longest_subsequence(lst[1:], prev)

  return mem[(tuple(lst),prev)]

print longest_subsequence([3,5,6,2,5,4,19,5,6,7,12])

請注意,使用tuple(list)作為您的動態狀態並不是一個好主意。 您可以簡單地使用您正在檢查的list中項目的索引而不是整個列表:

def longest_subsequence(lst, index=0, prev=None, mem={}):
  if index>=len(lst):
    return []
  if (index,prev) not in mem:
    if not prev or lst[index] > prev:
      mem[(index,prev)] = max([[lst[index]]+longest_subsequence(lst, index+1, lst[index]), longest_subsequence(lst, index+1, prev)], key=len)
    else:
      mem[(index,prev)] = longest_subsequence(lst,index+1, prev)

  return mem[(index,prev)]

print longest_subsequence([3,5,6,2,5,4,19,5,6,7,12])

對於更有效的方法,您可以檢查問題。

所以我剛剛發現 Tempux 的答案並不適用於所有情況。

我反復討論將整個狀態封裝到記憶字典中,因此添加了tuple(lis)作為鍵的一部分。 此外, lst索引技巧可能並不容易實現,因為我通過遞歸改變lst ,因此我使用tuple()作為我的鍵。

我所做的背后的原因是多個lis可能具有相同的[-1]值。 所以,有了這個新狀態,代碼是:

def longest_subsequence(lst, lis=[],mem={}):
  if not lst:
    return lis
  if (tuple(lst),tuple(lis)) not in mem:
    if not lis or lst[0] > lis[-1]:
      mem[(tuple(lst),tuple(lis))] = max([longest_subsequence(lst[1:], lis+[lst[0]]), longest_subsequence(lst[1:], lis)], key=len)
    else:
     mem[(tuple(lst),tuple(lis))] = longest_subsequence(lst[1:], lis)
  return mem[(tuple(lst),tuple(lis))]

這適用於我迄今為止測試過的所有情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM