Leetcode刷題第八周--動態規劃

終于講到動態規劃了,剛剛面完依圖,就考了動態規劃,在面試官的提示下才寫出來,要是認真刷過題就好了。

Leetcode 53. 最大子序和

給定一個整數數組 nums ,找到一個具有最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
示例:
輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,為 6。
進階:
如果你已經實現復雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。

解題思路一:動態規劃。比較前 i-1 個數的最大子序和+第i個數的和,與第i個數本身的大小比較。
解題思路二:

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = nums
        dp[0] = nums[0]
        ans = dp[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i-1] + nums[i], nums[i])
            if dp[i] > ans:
                ans = dp[i]
        return ans

Leetcode 120. 三角形最小路徑和

給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。
例如,給定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自頂向下的最小路徑和為 11(即,2 + 3 + 5 + 1 = 11)。
說明:
如果你可以只使用 O(n) 的額外空間(n 為三角形的總行數)來解決這個問題,那么你的算法會很加分。

解題思路:這個題很容易從上往下想,其實要自下而上來思考。


圖片.png
class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        n = len(triangle)
        i = n - 2
        while i >= 0:
            for j in range(i+1):
                triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
            i -= 1
        return triangle[0][0]

Leetcode 62. 不同路徑

一個機器人位于一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。
問總共有多少條不同的路徑?
例如,上圖是一個7 x 3 的網格。有多少可能的路徑?
說明:m 和 n 的值均不超過 100。
示例 1:
輸入: m = 3, n = 2
輸出: 3
示例 2:
輸入: m = 7, n = 3
輸出: 28

解題思路:動態規劃方法的經典應用,每一個點上面的路徑總數都等于它上面和左邊的點的路徑總數之和。注意這里的mn是列行而不是行*列。

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        if m == 1 or n == 1:
            return 1
        dp = [[1 for _ in range(m)] for _ in range(n)]
        for i in range(1, n):
            for j in range(1, m):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[n-1][m-1]

Leetcode 63. 不同路徑II

網格中的障礙物和空位置分別用 1 和 0 來表示。
說明:m 和 n 的值均不超過 100。
示例 1:
輸入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
輸出: 2

解題思路:創建一個dp的數組,全部為0,第一位為1-input[0][0],遞推公式為如果input[i][i] == 1的話,則dp[i][j]為0,否則dp[i][j] = dp[i-1][j]+dp[i][j-1]

class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        m = len(obstacleGrid)
        n = len(obstacleGrid[0])
        if m == 0:
            return 0
        if n == 0:
            return 0
        
        dp = [[0 for _ in range(n)] for _ in range(m)]
        dp[0][0] = 1 - obstacleGrid[0][0]

        for i in range(m):
            for j in range(n):
                if obstacleGrid[i][j] == 1:
                    dp[i][j] = 0
                else:
                    if i > 0:
                        dp[i][j] += dp[i-1][j] 
                    if j > 0:
                        dp[i][j] += dp[i][j-1]

        return dp[m-1][n-1]

Leetcode 91. 解碼方法

一條包含字母 A-Z 的消息通過以下方式進行了編碼:
'A' -> 1
'B' -> 2
...
'Z' -> 26
給定一個只包含數字的非空字符串,請計算解碼方法的總數。
示例 1:
輸入: "12"
輸出: 2
解釋: 它可以解碼為 "AB"(1 2)或者 "L"(12)。
示例 2:
輸入: "226"
輸出: 3
解釋: 它可以解碼為 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

解題思路:注意這里要把dp的長度擴大一位,相應的dp中對應的答案的序號也會后移一位。

class Solution(object):
    def numDecodings(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s[0] == '0' or s == None:
            return 0
        dp = [0] * (len(s) + 1)
        dp[0] = 1
        for i in range(1, len(dp)):
            if s[i-1] != '0':
                dp[i] = dp[i-1]
            if i != 1 and '09' < s[i-2:i] < '27':
                dp[i] += dp[i-2]
        return dp[-1]

Leetcode 198. 打家劫舍

(跪了跪了,去依圖現場面試的就是這道題,寫了好久好久,哭唧唧,應該多刷刷題的)

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 1:
輸入: [1,2,3,1]
輸出: 4
解釋: 偷竊 1 號房屋 (金額 = 1) ,然后偷竊 3 號房屋 (金額 = 3)。
偷竊到的最高金額 = 1 + 3 = 4 。
示例 2:
輸入: [2,7,9,3,1]
輸出: 12
解釋: 偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接著偷竊 5 號房屋 (金額 = 1)。
偷竊到的最高金額 = 2 + 9 + 1 = 12 。

解題思路:這里的動態規劃需要兩個變量,一個是偷前面一家,一個是不偷前面一家。

    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if n == 0:
            return 0
        
        f = nums[0]
        g = 0
        for i in range(1, n):
            last_f = f
            last_g = g
            f = g + nums[i]
            g = max(last_f, last_g)
            
        return max(f, g)

Leetcode 300. 最長上升子序列

給定一個無序的整數數組,找到其中最長上升子序列的長度。
示例:
輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
說明:
可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
你算法的時間復雜度應該為 O(n2) 。
進階: 你能將算法的時間復雜度降低到 O(n log n) 嗎?

解題思路:用數組dp[i]記錄以nums[i]結尾(即nums[i]為最后一個數字)的最長遞增子序列的長度,則遞推方程為dp[i]=max(dp[j]+1),其中要求1≤j<i且nums[j]<nums[i]。

時間復雜度分析:對每個i(1≤i≤n),都需要從1遍歷到i,則時間復雜度為O(n2),空間復雜度的話需要一個額外的dp數組,空間復雜度為O(n2)。

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if n <= 1:
            return n
        
        dp = [1 for _ in range(n)]
        length = 1
        
        for i in range(1, n):
            for j in range(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)
            length = max(length, dp[i])
        return length

Leetcode 72. 編輯距離

你可以對一個單詞進行如下三種操作:
插入一個字符
刪除一個字符
替換一個字符
示例 1:
輸入: word1 = "horse", word2 = "ros"
輸出: 3
解釋:
horse -> rorse (將 'h' 替換為 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')
示例 2:
輸入: word1 = "intention", word2 = "execution"
輸出: 5
解釋:
intention -> inention (刪除 't')
inention -> enention (將 'i' 替換為 'e')
enention -> exention (將 'n' 替換為 'x')
exention -> exection (將 'n' 替換為 'c')
exection -> execution (插入 'u')

解題思路:


圖片.png
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        n = len(word1)
        m = len(word2)
        if n == 0:
            return m
        if m == 0:
            return n
        f = [[0 for _ in range(m + 1)] for _ in range(n + 1)]
        for i in range(1, n+1):
            f[i][0] = i
        for i in range(1, m+1):
            f[0][i] = i
        for i in range(1, n+1):
            for j in range(1, m+1):
                if word1[i-1] == word2[j-1]:
                    f[i][j] = f[i-1][j-1]  
                else:
                    f[i][j] = f[i-1][j-1] + 1
                f[i][j] = min(f[i-1][j] + 1, f[i][j])
                f[i][j] = min(f[i][j-1] + 1, f[i][j])
        return f[n][m]

Leetcode 518. 零錢兌換II

給定不同面額的硬幣和一個總金額。寫出函數來計算可以湊成總金額的硬幣組合數。假設每一種面額的硬幣有無限個。
示例 1:
輸入: amount = 5, coins = [1, 2, 5]
輸出: 4
解釋: 有四種方式可以湊成總金額:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
示例 2:
輸入: amount = 3, coins = [2] 輸出: 0
你可以假設:
0 <= amount (總金額) <= 5000
1 <= coin (硬幣面額) <= 5000
硬幣種類不超過 500 種
結果符合 32 位符號整數

解題思路:


圖片.png
class Solution(object):
    def change(self, amount, coins):
        """
        :type amount: int
        :type coins: List[int]
        :rtype: int
        """
        
        n = len(coins)
        dp = [0 for _ in range(amount+1)]
        dp[0] = 1

        
        for i in range(n):
            j = coins[i]
            while j <= amount:
                dp[j] += dp[j-coins[i]]
                j += 1
        return dp[amount]

Leetcode 664. 奇怪的打印機

有臺奇怪的打印機有以下兩個特殊要求:
打印機每次只能打印同一個字符序列。
每次可以在任意起始和結束位置打印新字符,并且會覆蓋掉原來已有的字符。
給定一個只包含小寫英文字母的字符串,你的任務是計算這個打印機打印它需要的最少次數。
示例 1:
輸入: "aaabbb"
輸出: 2
解釋: 首先打印 "aaa" 然后打印 "bbb"。
示例 2:
輸入: "aba"
輸出: 2
解釋: 首先打印 "aaa" 然后在第二個位置打印 "b" 覆蓋掉原來的字符 'a'。

解題思路:


圖片.png
class Solution(object):
    def strangePrinter(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        if n == 0:
            return 0
        dp = [[0 for _ in range(n)] for _ in range(n)]
        for i in range(n):
            dp[i][i] = 1
        for length in range(1, n):
            for i in range(n-length):
                j = i + length
                dp[i][j] = 1 + dp[i+1][j]
                for k in range(i+1, j):
                    if s[i] == s[k]:
                        dp[i][j] = min(dp[i][j], dp[i][k-1] + dp[k+1][j])
                if s[i] == s[j]:
                    dp[i][j] = min(dp[i][j], dp[i+1][j])
                    
        return dp[0][n-1]

Leetcode 10. 正則表達式

給你一個字符串 s 和一個字符規律 p,請你來實現一個支持 '.' 和 '' 的正則表達式匹配。
'.' 匹配任意單個字符
'
' 匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋 整個 字符串 s的,而不是部分字符串。
說明:
s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字符 . 和
示例 1:
輸入:
s = "aa"
p = "a"
輸出: false
解釋: "a" 無法匹配 "aa" 整個字符串。
示例 2:
輸入:
s = "aa"
p = "a
"
輸出: true
解釋: 因為 '' 代表可以匹配零個或多個前面的那一個元素, 在這里前面的元素就是 'a'。因此,字符串 "aa" 可被視為 'a' 重復了一次。
示例 3:
輸入:
s = "ab"
p = ".
"
輸出: true
解釋: "." 表示可匹配零個或多個('')任意字符('.')。
示例 4:
輸入:
s = "aab"
p = "cab"
輸出: true
解釋: 因為 '' 表示零個或多個,這里 'c' 為 0 個, 'a' 被重復一次。因此可以匹配字符串 "aab"。
示例 5:
輸入:
s = "mississippi"
p = "mis
isp."
輸出: false

解題思路:


圖片.png
class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        n = len(s)
        m = len(p)
        s = ' ' + s
        p = ' ' + p
        f = [[False for _ in range(m + 1)] for _ in range(n + 1)]
        f[0][0] = True
        for i in range(n + 1):
            for j in range(1, m + 1):
                if i > 0 and (s[i] == p[j] or p[j] == '.'):
                    f[i][j] = f[i][j] or f[i-1][j-1]
                if p[j] == '*':
                    f[i][j] = f[i][j] or f[i][j-2]
                    if i > 0 and (s[i] == p[j-1] or p[j-1] == '.'):
                        f[i][j] = f[i][j] or f[i-1][j]
        return f[n][m]
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容