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
相关文章
相关标签/搜索