leetcode 动态规划小结

小试牛刀

题目:给定一个数组,判断是否存在子集之和为100

  1. 递归解法
# param:arr为数组, i为数组长度-1, target为目标数(100)
def recur_subset(arr, i, target):
	if arr[i] == target:
		return True
	if i == 0:
		return arr[0] == target
	if arr[i] > target:
		return dp_recur(arr, i-1, target)

	else:
		A = dp_recur(arr, i-1, target-arr[i])
		B = dp_recur(arr, i-1, target)

	return A or B

  1. 动态规划
import numpy as np 

# params: arr为给定数组, target为目标数(100)
def dp_subset(arr, target):

	length = len(arr)
	
	# 纵向为arr的元素索引, 横向为target
	dp = np.zeros((len(arr), target+1))

	# 当到达arr[0]时, 将与arr[0]不相等的置为False, 相等的置为True
	dp[0, :] = False
	# 当target为0时,返回True, 即二维dp第一列为True
	dp[:, 0] = True

	# 判断界限, 如果arr[0]>target则越界
	if arr[0] < target:
		dp[0, arr[0]] = True

	for i in range(1, len(arr)):
		for j in range(1, target+1):
			if arr[i] > j:
				dp[i, j] = dp[i-1, j]
			else:
				A = dp[i-1, j-arr[i]]
				B = dp[i-1, j]
				dp[i, j] = A or B

	print(dp)
	return dp[-1, -1]

leetcode 5. 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

示例 2:

输入: “cbbd”
输出: “bb”

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解(动态规划):

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        if len(s) <= 1:
        	return s
        
        length = len(s)
		
		# 创建dp二维列表
		dp = [[False for _ in range(length)] for _ in range(length)]
		
		max_length = 1
		res = s[0]

		for r in range(1, length):
			for l in range(r):
				# 若首s[l]尾s[r]相等, 且中间的子串也是回文串 或者 子长度小于等于1, 则此为回文串
				if s[l] == s[r] and (r-l <= 2 or d[l+1][r-1]):
					dp[l][r] = True

					cur_length = r - l + 1
					if cur_length > max_length:
						max_length = cur_length
						res = s[l:r+1]
		
		return res

leetcode 53. 最大子序列和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = nums[0]
        max_sum = 0
        
        for i in nums:
            if max_sum > 0:
                max_sum += i
            else:
                max_sum = i
            
            res = max(res, max_sum)
        
        return res

leetcode 62. 不同路径Ⅰ

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?
在这里插入图片描述
例如,上图是一个7 x 3 的网格。有多少可能的路径?

说明:m 和 n 的值均不超过 100。

示例 1:

输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向右 -> 向下
  2. 向右 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向右

示例 2:

输入: m = 7, n = 3
输出: 28

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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 = [[0 for _ in range(m)] for _ in range(n)]
        
        for i in range(n):
            for j in range(m):
                if i == 0:
                    dp[i][j] = 1
                if j == 0:
                    dp[i][j] = 1
                else:
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
        # print(dp)
        return dp[-1][-1]

leetcode 63. 不同路径Ⅱ

一个机器人位于一个 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. 向下 -> 向下 -> 向右 -> 向右

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        row = len(obstacleGrid)
        col = len(obstacleGrid[0])
        
        dp = [[0 for _ in range(col)] for _ in range(row)]    

        for i in range(row):
            for j in range(col):
                if obstacleGrid[i][j] == 1:                
                    dp[i][j] = 0
                    continue
                
                if i == 0 and j == 0:
                    if obstacleGrid[i][j] == 1:
                        return 0
                    else:
                        dp[i][j] = 1
                        
                elif i == 0 and j >= 1:
                    print('xbb')
                    dp[i][j] = dp[i][j-1]
                elif j == 0 and i >= 1:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = dp[i][j-1] + dp[i-1][j]
                
        return dp[-1][-1]

leetcode 120. 三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

例如,给定三角形:

[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]

自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/triangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if len(triangle) == 0:
            return 0
        
        # 从倒数第二行依次遍历每一行
        row = len(triangle) - 2
        
        for i in range(row, -1, -1):
            for j in range(len(triangle[i])):
                # 取下一行相邻得两个数中较小的与之相加
                triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])

        return triangle[0][0]
        

leetcode 121. 买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路一

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        buy = prices[0]

        profit = [0 for _ in range(len(prices))]

        for i in range(len(prices)):
        	if prices[i] > buy:
        		profit[i] = prices[i] - buy
        	else:
        		buy = prices[i]

        return max(profit)

思路二

class Solution_1(object):

    def maxProfit(self, prices):

        min_price = prices[0]
        max_profit = 0
        for i in range(len(prices)):
            min_price = min(min_price, prices[i])
            max_profit = max(max_profit, prices[i] - min_price)

        return max_profit

leetcode 122. 买卖股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

算法一:峰谷法
假设给定的数组为:
[7, 1, 5, 3, 6, 4]
如果我们在图表上绘制给定数组中的数字,我们将会得到:
在这里插入图片描述

如果我们分析图表,那么我们的兴趣点是连续的峰和谷。
用数学语言描述为:
在这里插入图片描述
关键是我们需要考虑到紧跟谷的每一个峰值以最大化利润。如果我们试图跳过其中一个峰值来获取更多利润,那么我们最终将失去其中一笔交易中获得的利润,从而导致总利润的降低。
例如,在上述情况下,如果我们跳过 peak_i 和 valley_j​ 试图通过考虑差异较大的点以获取更多的利润,获得的净利润总是会小与包含它们而获得的静利润,因为 C 总是小于 A+B。

作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
		if len(prices) < 2:
            return 0
		
        profit = 0 
        peek = prices[0]
        valley = prices[0]
        
        i = 0
        while i < len(prices)-1:
            while i < len(prices)-1 and prices[i] >= prices[i+1]:
                i += 1
            valley = prices[i]
            
            while i < len(prices)-1 and prices[i] <= prices[i+1]:
                i += 1
            peek = prices[i]
            
            profit += peek - valley
        
        return profit

算法二:简单的一次遍历
[1, 7, 2, 3, 6, 7, 6, 7]
与此数组对应的图形是:
在这里插入图片描述

从上图中,我们可以观察到 A+B+C 的和等于差值 D 所对应的连续峰和谷的高度之差。

作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if len(prices) < 2:
            return 0
            
        profit = 0
        for i in range(len(prices)-1):
            if prices[i+1] > prices[i]:
                profit += prices[i+1] - prices[i]
        return profit

leetcode上其他买卖股票的题型:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/yi-ge-tong-yong-fang-fa-tuan-mie-6-dao-gu-piao-wen/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值