1. 題目內容
給定一個無序的整數數組,找到其中最長上升子序列的長度。
示例:
輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
說明:
- 可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
- 你算法的時間複雜度應該爲 O(n2) 。
進階: 你能將算法的時間複雜度降低到 O(n log n) 嗎?
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
2. 基本思路
來自極客時間的課程,覃超老師講的,現在做筆記記錄如下:
- 創建一個數組
l
用於記錄當前的滿足要求的最長的子序列;- 遍歷整個數組,並調整數組
l
;- 調整規則如下:
<1> 若當前元素大於數組l
中所有元素,則l
長度加一,將當前元素添加入l
<2> 否則,找到l
中比當前元素大的元素中的最小值,用當前元素替換,使用二分查找(這也是時間複雜度中logN的來源);
<3> 遍歷完畢後返回l
的長度即可
3. 代碼實現(Python)
class Solution(object):
def binary_search(self, num, lts): # 二分查找,找到當前元素的插入位置
l = len(lts)
left = 0
right = l - 1
while left < right:
mid = (left + right) // 2
if lts[mid] < num < lts[mid+1]:
return mid+1
elif num > lts[mid]:
left = mid+1
else:
right = mid
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
lts = [nums[0]]
for num in nums[1:]:
if num > lts[-1]:
lts.append(num)
elif num < lts[0]:
lts[0] = num
elif num in lts:
continue
elif num < lts[-1]:
n_l = self.binary_search(num, lts)
lts[n_l] = num
print(lts)
return len(lts)
def main():
nums = [10, 9, 2, 5, 3, 7, 101, 18, 20]
a = Solution()
res = a.lengthOfLIS(nums)
# print(res)
if __name__ == '__main__':
main()
對於main()
中給出的數組,遍歷時子序列數組內容依次爲:
[10]
[9]
[2]
[2, 5]
[2, 3]
[2, 3, 7]
[2, 3, 7, 101]
[2, 3, 7, 18]
[2, 3, 7, 18, 20]
4. 小結
本題較爲常規的解法似乎是動態規劃,時間複雜度爲O(N^2),本文的解法似乎屬於奇技淫巧型,但細想之下會覺得這是需要基礎非常牢靠才能想得出的解法,因此記錄一下。
此外,這一次順便複習了二分查找的寫法,發現之前掌握的很不牢靠,自己寫的很痛苦,想用遞歸實現,後來去搜了一個例子,才學會,而且更新 left 或 right 的時候需要實際寫一下看看要不要 mid±1.