最大子序和、最長上升子序列長度

數據來源:https://leetcode-cn.com/problems/longest-increasing-subsequence/css

最大子序和算法

   給定一個整數數組 nums ,找到一個具備最大和的連續子數組(子數組最少包含一個元素),返回其最大和。數組

  代碼以下所示:app

 1 class Solution:
 2     def maxSubArray(self, nums: List[int]) -> int:
 3         length = len(nums)
 4         if length==1:
 5             return nums[0]
 6         max_ret = nums[0]
 7         cur_max = last_max = nums[0]
 8         for i in range(1, length):
 9             if last_max + nums[i] < nums[i]:
10                 cur_max = nums[i]
11             else:
12                 cur_max = last_max + nums[i]
13             if cur_max > max_ret:
14                 max_ret = cur_max
15             last_max = cur_max
16         return max_ret

 

最長上升子序列長度ui

  給定一個無序的整數數組,找到其中最長上升子序列的長度。spa

  動態規劃求解指針

    思路:利用動態規劃的思想,咱們能夠將問題分解爲到第i個元素的最長上升子序列長度的子問題。利用mem列表記錄列表第一個元素到第 i 個元素的最長上升子序列長度,cur_mem變量記錄了當前元素與 mem[j<i] 對應的子序列構成的 i-1 個子序列的最長上升子序列長度。代碼以下所示:code

 1 class Solution0:
 2     def lengthOfLIS(self, nums) -> int:
 3         if len(nums) == 0:
 4             return 0
 5         mem = [1 for _ in range(len(nums))]
 6         for i in range(1, len(nums)):
 7             cur_mem = []
 8             for j in range(i):
 9                 if nums[i] > nums[j]:
10                     cur_mem.append(mem[j] + 1)
11                 else:
12                     cur_mem.append(1)                        
13             mem[i] = max(cur_mem)
14             print(mem)
15         return max(mem)

    算法的時間複雜度爲:O(n^2),空間複雜度O(n)。blog

    白話:咱們求第 i 個元素對應的最長上升子序列時,是求包含nums[i] 這個元素的最長子序列長度;轉移狀態即爲:當前元素加到mem[j],j<i 對應的子序列後,是否仍是上升子序列,將是上升子序列的在對應的mem[j]上加1保存到cur_mem中,若不是,則保存1,最後將cur_mem中最大的元素保存爲nums[i] ,最後輸出mem中最大的元素即爲最長上升子序列的長度。索引

  動態規劃 + 二分查找

    在上面的解法中,變量列表nums是不可避免的;可是在循環裏的每一步咱們都須要計算 j 次(j<i),該循環的時間複雜度爲O(n),這裏的簡化爲使用二分法查找該長度,將時間複雜度將爲O(log(n))。

    思路:引入一個與nums等長的全零列表tails;定義兩個指針 i, j ;循環列表nums,在每次循環進行以下操做:

       一、i,j表示要查詢的範圍(索引),進行內層循環 while i<j;

       二、在內層循環中計算區間中:m = (i+j) // 2;

       三、計算tails[m]是否小於外層循環值num,若小於num,則令i = m+1;不然 j = m;

       四、內層循環結束時,將 tails[i] 賦值爲 num。這裏結合內層循環實現的功能是:外層循環的值若大於tails最後一個非零值則替換尾部的第一個零元素,若比它小,則替換前面序列中的一個數,這個數的前一個數比本身小(或不存在),後一個數比本身大(或不存在),注意,tails中的非零部分是嚴格上升序列,雖然順序和原序列不必定同樣,可是均可以映射爲原序列中的一個子序列,也即最長子序列的長度同樣。

 1 class Solution1:
 2     def lengthOfLIS(self, nums: [int]) -> int:
 3         tails, res = [0] * len(nums), 0
 4         for num in nums:
 5             i, j = 0, res
 6             while i < j:
 7                 m = (i + j) // 2
 8                 if tails[m] < num: i = m + 1 # 若是要求非嚴格遞增,將此行 '<' 改成 '<=' 便可。
 9                 else: j = m
10             tails[i] = num
11             print(tails)
12             if j == res: res += 1
13         return res

    此算法引用:最長上升子序列(動態規劃 + 二分查找,清晰圖解)

相關文章
相關標籤/搜索