微軟演算法面試題:如何找最長的增長子序列

2018-03-20    分類:演算法設計、程式設計開發、首頁精華0人評論發表於2018-03-20

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

這個問題是微軟提出來的。

給定一組數字,找出陣列中最長的增長子序列的長度。子序列不一定必須是連續的。

例如,給定陣列[0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15],最長的增長子序列的長度為6:它是0,2,6,9,11,15。

解決方案

解決這個問題的蠻力方法是生成每個可能的子序列,然後測試每個子序列的單調性並保持跟蹤最長的那個。這將非常昂貴:生成每個子序列就得O(2^N)!

相反,我們可以試著用遞迴來解決這個問題,然後用動態程式設計來優化。

假設我們已經有了一個函式,這個函式給了我們最長增長子序列的長度。然後我們將試著將輸入陣列的一部分反饋給它並嘗試擴充套件結果。基本情況是:空列表,返回0;有一個元素的陣列,返回1。

然後

  • 對於直到倒數第二個元素為止的每個索引i,計算longest_increasing_subsequence到那裡為止。
  • 如果最後一個元素大於arr[i],我們就用最後一個元素來擴充套件結果(因為否則它就不是增長的了)。
  • 保持跟蹤最大的結果。
def longest_increasing_subsequence(arr):
    if not arr:
        return 0
    if len(arr) == 1:
        return 1

    max_ending_here = 0
    for i in range(len(arr)):
        ending_at_i = longest_increasing_subsequence(arr[:i])
        if arr[-1] > arr[i - 1] and ending_at_i + 1 > max_ending_here:
            max_ending_here = ending_at_i + 1
    return max_ending_here

由於重複的子計算(指數時間),所以這會非常非常慢。因此,讓我們通過動態程式設計來儲存值以便稍後重新計算它們。

我們將儲存一個長度為N的陣列A,並且A[i]將包含以i結尾的最長增長子序列的長度。然後,我們可以使用相同的遞迴迴圈,轉而在陣列中查詢:

def longest_increasing_subsequence(arr):
    if not arr:
        return 0
    cache = [1] * len(arr)
    for i in range(1, len(arr)):
        for j in range(i):
            if arr[i] > arr[j]:
                cache[i] = max(cache[i], cache[j] + 1)
    return max(cache)

現在的時間複雜度和空間複雜度為O(N^2)和 O(N)。

你是正在準備面試程式設計工作,還是正享受於程式設計的樂趣中?不管怎樣,知識是靠積累的。祝編碼快樂!

譯文連結:http://www.codeceo.com/article/find-the-longest-increasing-subsequence.html
英文原文:How to Find the Longest Increasing Subsequence
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章