leetcode 動態規劃整理

動態規劃整理

1.最長公共子序列 leetcode300

# 給定兩個字符串 text1 和 text2,返回這兩個字符串的最長公共子序列。
# 
# 一個字符串的 子序列 是指這樣一個新的字符串:它是由原字符串在不改變字符的相對順序的狀況下刪除某些字符(也能夠不刪除任何字符)後組成的新字符串。
# 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde"
# 的子序列。兩個字符串的「公共子序列」是這兩個字符串所共同擁有的子序列。
# 
# 若這兩個字符串沒有公共子序列,則返回 0。

# 示例 1:
# 
# 輸入:text1 = "abcde", text2 = "ace" 
# 輸出:3  
# 解釋:最長公共子序列是 "ace",它的長度爲 3。

class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        """
        :type text1: str
        :type text2: str
        :rtype: int
        """
        m,n=len(text1),len(text2)
        dp=[[0 for _ in range(m+1)] for _ in range(n+1)]
        for i in range(1,n+1):
            for j in range(1,m+1):
                str1=text1[:j]
                str2=text2[:i]
                if str1[-1]==str2[-1]:
                    dp[i][j]=dp[i-1][j-1]+1
                else:
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1])
        return dp[-1][-1]

2.最長上升子序列 leetcode300

# 給定一個無序的整數數組,找到其中最長上升子序列的長度。
# 
# 示例:
# 
# 輸入: [10,9,2,5,3,7,101,18]
# 輸出: 4 
# 解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
# 
# 說明:

# 可能會有多種最長上升子序列的組合,你只須要輸出對應的長度便可。
# 你算法的時間複雜度應該爲 O(n^2) 。
# 
# 
# 進階: 你能將算法的時間複雜度下降到 O(n log n) 嗎?
#

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:return 0
        dp=[1]*len(nums)	#dp[i]表示到i位置的最長上升子序列
        for i in range(1,len(nums)):
            for j in range(i):
                if nums[i] > nums[j]:		#每掃描到一個數,遍歷在它以前的數字,選擇比它小的
                    dp[i] = max(dp[i],dp[j] + 1)	#狀態轉移
        # 最後要所有走一遍,看最大值
        return max(dp)

3.爬樓梯 leetcode70

# 假設你正在爬樓梯。須要 n 階你才能到達樓頂。
# 
# 每次你能夠爬 1 或 2 個臺階。你有多少種不一樣的方法能夠爬到樓頂呢?
# 
# 注意:給定 n 是一個正整數。
# 最核心的轉移方程是res[i] = res[i-1] + res[i-2]
def climbStairs2(self, n):
    if n == 1:
        return 1
    res = [0 for i in xrange(n)]
    res[0], res[1] = 1, 2
    for i in xrange(2, n):
        res[i] = res[i-1] + res[i-2]
    return res[-1]

4.最長公共子串

#給兩個字符串,返回它們的最長公共子串的長度
#方法和最長公共子序列同樣,不過最終造成的二維數組中子串應該連成一條斜線。
class Solution(object):
    def LCS(self,str1,str2):
        if not str1 or not str2:return 0
        dp=[[0 for _ in range(len(str1))] for _ in range(len(str2))]
        res=0
        
        for j in range(len(str1)):
            if str1[j]==str2[0]:
                dp[0][j]=1

        for i in range(len(str2)):
            if str2[i]==str1[0]:
                dp[i][0]=1

        for i in range(1,len(str2)):
            for j in range(1,len(str1)):
                if str1[j]==str2[i]:
                    dp[i][j]=dp[i-1][j-1]+1
                    res=max(res,dp[i][j])
        return res

4.單詞拆分 leetcode139

# 給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,斷定 s 是否能夠被空格拆分爲一個或多個在字典中出現的單詞。
# 
# 說明:
# 
# 
# 拆分時能夠重複使用字典中的單詞。
# 你能夠假設字典中沒有重複的單詞。
# 
# 
# 示例 1:
# 
# 輸入: s = "leetcode", wordDict = ["leet", "code"]
# 輸出: true
# 解釋: 返回 true 由於 "leetcode" 能夠被拆分紅 "leet code"。
# 
# 
# 示例 2:
# 
# 輸入: s = "applepenapple", wordDict = ["apple", "pen"]
# 輸出: true
# 解釋: 返回 true 由於 "applepenapple" 能夠被拆分紅 "apple pen apple"。
# 注意你能夠重複使用字典中的單詞。
# 
# 
# 示例 3:
# 
# 輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
# 輸出: false
# 
# 

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        n=len(s)
        dp=[False]*(n+1)
        dp[0]=True              #這裏的dp[0]=True並不表示位置,而是表示一種初始狀態
        for i in range(1,n+1):
            for word in wordDict:       #同一個位置可能有好幾種到達的方式,因此要遍歷wordDict
                if i>=len(word) and dp[i-len(word)] and s[i-len(word):i]==word:
                    dp[i]=True          #dp[i]爲True表示從頭分割的話能夠分割到第i個位置來
                                        
        return dp[-1]

5.不一樣路徑II leetcode63

# 一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記爲「Start」 )。
# 
# 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記爲「Finish」)。
# 
# 如今考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不一樣的路徑?
# 
# 
# 
# 網格中的障礙物和空位置分別用 1 和 0 來表示。
# 
# 說明:m 和 n 的值均不超過 100。
# 
# 示例 1:
# 
# 輸入:
# [
# [0,0,0],
# [0,1,0],
# [0,0,0]
# ]
# 輸出: 2
# 解釋:
# 3x3 網格的正中間有一個障礙物。
# 從左上角到右下角一共有 2 條不一樣的路徑:
# 1. 向右 -> 向右 -> 向下 -> 向下
# 2. 向下 -> 向下 -> 向右 -> 向右
# 
# 
#
class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        if not obstacleGrid:return 0
        row_len=len(obstacleGrid)
        col_len=len(obstacleGrid[0])
        obstacleGrid[0][0] =1-obstacleGrid[0][0]
        for r in range(1,row_len):	#初始化第一列,若是有1就把以後的都設爲0,由於擋住了怎麼也到不了
            obstacleGrid[r][0]=obstacleGrid[r-1][0]*(obstacleGrid[r][0]==0)
        for c in range(1,col_len):	#初始化第一行
            obstacleGrid[0][c]=obstacleGrid[0][c-1]*(obstacleGrid[0][c]==0)
        for r in range(1,row_len):
            for c in range(1,col_len):	 #到達一個位置的方法數=從上面到達的方法數+從左邊到達的方法數
                obstacleGrid[r][c]=(obstacleGrid[r-1][c]+obstacleGrid[r][c-1])*(obstacleGrid[r][c]==0)
        return obstacleGrid[-1][-1]

6.三角形的最小路徑

# 給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。
# 
# 例如,給定三角形:
# 
# [
# ⁠    [2],
# ⁠   [3,4],
# ⁠  [6,5,7],
# ⁠ [4,1,8,3]
# ]
# 
# 
# 自頂向下的最小路徑和爲 11(即,2 + 3 + 5 + 1 = 11)。
# 
# 說明:
# 
# 若是你能夠只使用 O(n) 的額外空間(n 爲三角形的總行數)來解決這個問題,那麼你的算法會很加分。
# 
#
class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        for i in range(1,len(triangle)):
            for j in range(len(triangle[i])):
                if j==0:	#最左邊
                    triangle[i][j]=triangle[i-1][j]+triangle[i][j]
                elif j==len(triangle[i])-1:	#最右邊
                    triangle[i][j]=triangle[i-1][j-1]+triangle[i][j]
                else:	#到達這個位置的路徑和=上面兩種到達方法更小的那種+這個位置的權值
                    triangle[i][j]=min(triangle[i-1][j],triangle[i-1][j-1])+triangle[i][j]
        return min(triangle[-1])

7.最大正方形 leetcode221

# 在一個由 0 和 1 組成的二維矩陣內,找到只包含 1 的最大正方形,並返回其面積。
# 
# 示例:
# 
# 輸入: 
# 

# Testcase Example:  
#'[["1","0","1","0","0"],
#  ["1","0","1","1","1"],
#  ["1","1","1","1","1"],
#  ["1","0","0","1","0"]]'
#
# 輸出: 4
class Solution(object):
    def maximalSquare(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if not matrix:return 0
        res=0
        row=len(matrix)
        col=len(matrix[0])
        dp=[[0 for _ in range(col+1)] for _ in range(row+1)]
        
        for i in range(1,row+1):
            for j in range(1,col+1):
                if matrix[i-1][j-1]=='1':	#只有當matrix[i][j]爲1,且上面,左邊,左上角都不爲0的時																				#候,才能夠組成正方形,而且將dp[i][j]更新爲正方形的邊長
                    dp[i][j]=min(int(dp[i-1][j-1]),int(dp[i-1][j]),int(dp[i][j-1]))+1
                    res=max(res,dp[i][j])		#存一下最大邊長
        return res*res

8.二位矩陣區域和檢索-矩陣不可變 leetcode304

# 給定一個二維矩陣,計算其子矩形範圍內元素的總和,該子矩陣的左上角爲 (row1, col1) ,右下角爲 (row2, col2)。
# 
# 
# 上圖子矩陣左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),該子矩形內元素的總和爲 8。
# 
# 示例:
# 
# 給定 matrix = [
# ⁠ [3, 0, 1, 4, 2],
# ⁠ [5, 6, 3, 2, 1],
# ⁠ [1, 2, 0, 1, 5],
# ⁠ [4, 1, 0, 1, 7],
# ⁠ [1, 0, 3, 0, 5]
# ]
# 
# sumRegion(2, 1, 4, 3) -> 8
# sumRegion(1, 1, 2, 2) -> 11
# sumRegion(1, 2, 2, 4) -> 12
# 
# 
# 說明:
# 
# 
# 你能夠假設矩陣不可變。
# 會屢次調用 sumRegion 方法。
# 你能夠假設 row1 ≤ row2 且 col1 ≤ col2。
# 題目說會屢次調用,咱們直接定義一個新矩陣,sums[i][j]表示從matrix[0][0]到此位置圍成的正方形的面積,下次計算的時候直接用sums[row2][col2]-sums[row2][col1-1]-sums[row1-1][col2]+sums[row1-1][col1-1]

class NumMatrix(object):

    def __init__(self, matrix):
        """
        :type matrix: List[List[int]]
        """
        if not matrix:
            return 
        m=len(matrix)+1
        n=len(matrix[0])+1
        self.sums=[[0 for _ in range(n)] for _ in range(m)]
        for i in range(1,m):
            for j in range(1,n):
                self.sums[i][j]=matrix[i-1][j-1]+self.sums[i-1][j]+self.sums[i][j-1]-self.sums[i-1][j-1]

    def sumRegion(self, row1, col1, row2, col2):
        """
        :type row1: int
        :type col1: int
        :type row2: int
        :type col2: int
        :rtype: int
        """
        row1, col1, row2, col2=row1+1,col1+1,row2+1,col2+1
        return self.sums[row2][col2]-self.sums[row2][col1-1]-self.sums[row1-1][col2]+self.sums[row1-1][col1-1]


# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# param_1 = obj.sumRegion(row1,col1,row2,col2)

9.零錢兌換 leetcode322

# 給定不一樣面額的硬幣 coins 和一個總金額
# amount。編寫一個函數來計算能夠湊成總金額所需的最少的硬幣個數。若是沒有任何一種硬幣組合能組成總金額,返回 -1。
# 
# 示例 1:
# 
# 輸入: coins = [1, 2, 5], amount = 11
# 輸出: 3 
# 解釋: 11 = 5 + 5 + 1
# 
# 示例 2:
# 
# 輸入: coins = [2], amount = 3
# 輸出: -1
# 
# 說明:
# 你能夠認爲每種硬幣的數量是無限的。
# 
#

# @lc code=start
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp=[float('inf')]*(amount+1)
        dp[0]=0
        for i in range(1,amount+1):
            for coin in coins:
                if i>=coin:
                    dp[i]=min(dp[i],dp[i-coin]+1)
        return dp[-1] if dp[-1]!=float('inf') else -1
相關文章
相關標籤/搜索