Python 刷題筆記:一道簡單級的動態規劃題

今天翻看了關於時間複雜度、空間複雜度的文章和視頻,對其認知加深了些,之後也要養成分析複雜度的習慣,順手添加,大家如果看到我寫錯的還望予以糾正。

同時,今兒還遇到句值得反思的話:“珍惜你所遇見的每一道題”。目前刷題 41 天,LeetCode 上題目刷了 80 道。但如果讓我重新再做,應該有不少題目還是搞不定,甚至會出現之前做出來、現在看卻沒思路的情況。此外,之前有些簡單題目是利用 Python 取巧通關,繞開了題目本身關聯的算法設計,使得做題純粹變成了做任務,白白浪費練習算法、加深理解的機會。

所以,認真對待遇到的每一個題目,整理、理解、吃透它,這樣自己花費在其中的時間纔會發揮最大價值。

迴歸到題目,今兒仍是動態規劃的題目,題目確實簡單級別——這道題之前我通過分情況考慮,設計了一套複雜解法,與接下來要整理的動態規劃可謂鮮明對比。

題目

「第 53 題:最大子序和」

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

示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。

題目分析

先說下我之前的複雜思路:因爲數組中可能有正有負,先將連續正、或連續負的數合併,這樣列表如果全正、最大和爲數組和;如果列表全負、最大和爲最大的單項值;如果有正有負、合併後就會正負相間,通過比較相鄰正負相加後的結果來判斷是否計入最大和中。

聽着很繞,實施起來也不簡單,費白天功夫、通過各種特例補全了整個代碼思路。接下來我們對比看下動態規劃的設計。

首先要設計狀態,dp [ i ] 我們定義爲以數組 nums [ i ] 結尾的連續子數組的最大和——可能我們會有疑問,這個狀態怎麼找的?注意,動態規劃最關鍵的就是找準狀態和狀態轉移方程,如何找準這個要麼憑理論分析、要麼就是多做題積累經驗。這也是我們翻看很多講解、分析老是說動態規劃不難、很簡單的原因:因爲人家的積累和經驗在那擺着,見怪不怪了,對於剛接觸這類題型的我們就好奇寶寶似的滿腦袋問號。如果還記得昨天做過的揹包問題,也是定義了類似在 i 位置的揹包最大價值,這裏定義要以 i 位置結尾的子數組,就是爲了可以和 dp [ i-1 ] 建立直接聯繫。

有了上面的狀態定義,找狀態轉移方程就會輕鬆些,在計算 dp[ i ] 時,我們可以拿到的有以 nums[i-1] 項結尾的子數組的最大和 dp[i-1] 和 nums[ i ]。根據狀態定義,以 nums[i] 結尾的子數組,那麼計算和一定有 nums[i] 參與,再看之前的項,倘若 dp[i-1] 爲負,那麼最大和就不必添加這部分;但如果其爲正,則將其加入進來即可。完畢~

是的,這就完事了,上代碼。

代碼實現

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        # 對單項數組單獨處理
        if n==1:
            return nums[0]


        # dp[i] 爲以 nums[i] 結尾的連續子數組最大和
        dp = [0]*n
        # 初始化 dp 數組爲 n 個 0 的列表
        dp[0] = nums[0]
    
        # 遍歷每一位
        for i in range(1,n):
          # dp[i-1]即以 nums[i-1] 結尾的子數組最大和
          # 如果 dp[i-1] 非正,則不加
            if dp[i-1]<=0:
                dp[i] = nums[i]
            # 如果正,則加起來
            else:
                dp[i] = dp[i-1]+nums[i]
        # 返回 dp 記錄列表的最大值
        return max(dp)

因爲我們通過對 n 位數組的一次遍歷建立了所謂的狀態列表,最後執行了次求最大值運輸,整體時間複雜度與 n 成線性關係,即 O(n) 時間複雜度;在整個過程中,額外建立了 dp 這個長度爲 n 的數組或列表,空間複雜度也爲 O(n)。

提交測試表現:

執行用時 : 44 ms, 在所有 Python3 提交中擊敗了 89.29% 的用戶
內存消耗 : 14.8 MB, 在所有 Python3 提交中擊敗了 6.35% 的用戶

後記

這道題的複雜解法是幾天前費大工夫寫的,當時題目通過了就沒理了;今天按動態規劃標籤翻到這道簡單題目,對當時的解法半天才反應過來,又花費好長時間想動態規劃的解法卻一直沒能找到準確的狀態。當看到題解裏對此狀態的定義時,豁然開朗。

是的,雖然我記錄了整篇,但下次遇到時,卻又不能保證一定記得,真是可惜。所以,珍惜這些遇到過的題目,時不時翻看懷念它們一下吧。在接下來刷題的道路上,我也要更看重質量和算法設計,忽略浮於表面的題目難度、數量、速度這些概念了。

本來寫題記的,結果囉嗦一大堆,哈哈~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章