leetcode刷题记录:算法(九)动态规划
动态规划(Dynamic Programming,DP)
根据百度百科上的定义:
动态规划是求解决策过程最优化的过程
然后各个博客里对动态规划的描述为:
将需要求解的大问题,分解为一个个的小问题,并在计算过程中保存每个小问题的结果以避免重复计算。
动态规划是一种以空间换时间的技术。我看了几个例子,感觉动态规划其实是递归的反推:
递归: 从要求的的问题(顶层)开始,一层一层递归到出口条件,然后再逐层返回
动态规划: 从出口条件开始 ,逐层上升到要求解的问题。
动态规划感觉是迄今为止最难理解的一种算法了,我找了些资料看,感觉还是没有领会到精髓,做题熟悉吧。
70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
爬到第n阶有两种可能
- 现在站在第n-2阶,再一次性爬两阶;
- 现在站在第n-1阶,再爬一阶
假设两种情况分别包含f(n-2)和f(n-1)种可能,爬到第n层有f(n)种可能,那么有:
f(n) = f(n-1) + f(n-2)
这就是本道题的状态转移方程。同时本题的边界条件:
f(0) = 1, f(1) = 1
接下来题就很好解了
class Solution:def climbStairs(self, n: int) -> int:if n==0 or n==1:return 1dn = [0]*(n+1)dn[0] = 1dn[1] = 1for i in range(2, n+1):dn[i] = dn[i-1]+dn[i-2]return dn[n]
121 买卖股票的最佳时机
和上一道题不一样,买卖股票涉及到买和卖两种情况,不能单纯的用一个一维数组去维护历史结果。
很容易理解:
第n天卖出的收益为,当天的股票价格减去第n-1天之前的最低买入价格,即:
sell[n] = prices[n] - min_buy[n-1]
第n天卖出的最大收益为,当天卖出收益和历史最大收益中较大的那个,即:
max_sell[n] = max (max_sell[n-1], prices[n] - min_buy[n-1])
而最低买入价格很好求,为
min_buy[n] = min(min_buy[n-1], prices[n])
所以代码为:
class Solution:def maxProfit(self, prices: List[int]) -> int:# 注释掉的部分为更节省空间和时间的做法# 但是我对这是不是动态规划表示怀疑# 所以还是写了个笨笨的真正的动态规划# 两者的差别就是前一种做法只维护了两个常量# if prices == []:# return 0# min_in = prices[0]# max_out = 0# for i in range(len(prices)):# min_in = min(min_in, prices[i])# max_out = max(max_out,prices[i]- min_in)# return max_outif prices == []:return 0min_buy, max_sell = [0]*len(prices), [0]*len(prices)min_buy[0] = prices[0]for i in range(1,len(prices)):min_buy[i] = min(min_buy[i-1], prices[i])max_sell[i] = max(max_sell[i-1],prices[i]- min_buy[i-1])return max(max_sell)
5 最长回文子串
一开始看到这道题的时候,想用滑动窗口解,因为回文串存在两种情况:
- aba
- abba
所以要用宽度为2和3的窗口分别遍历整个字符串,找到回文串的“种子”后,以这个种子为中心进行扩展,寻找最长的字符串,每次的时间复杂度为O(N),整体的时间复杂度也是O(N)
动态规划法没什么思路,看了答案,总结如下:
对于给定长度为N的字符串s,如果存在一个子串s[i:j]是回文串,那么必然有s[i+1,j-1]必然是回文串,如果以P[i, j]来记录s[i, j]是不是回文串,则有:
P[i,j]=P[i+1,j−1]∧(Si==Sj)P[i,j] = P[i+1,j-1]∧(S i==S j) P[i,j]=P[i+1,j−1]∧(Si==Sj)
这就是状态转移方程。
至于边界,如我之前描述的两种回文串,有:
P[i,i]=True,P[i,i+1]=(Si==Si+1)P[i,i] = True, P[i,i+1] = (Si==Si+1) P[i,i]=True,P[i,i+1]=(Si==Si+1)
最终答案为所有值为True的P(i,j)中,j-i+1最大的那个。
还一个需要注意的是,不能用两个指针取遍历,那样会漏掉一些结果,我就吃了这个亏吃了很久,用pycharm进行debug才发现这一点,比如:
s =‘aaaaa’
如果我用双循环进行遍历:
for i in range(n):for j in range(i,n):pass
那我们会先得到i=0,j=4,此时P(1,3)还没能进行数据更新,还是False,导致P(0,4)判断错误。
所以需要以长度进行遍历。
class Solution:def longestPalindrome(self, s: str) -> str:n = len(s)dp = [[False] * n for _ in range(n)]ans = ""# 枚举子串的长度 l+1for l in range(n):# 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置for i in range(n):j = i + lif j >= len(s):breakif l == 0:dp[i][j] = Trueelif l == 1:dp[i][j] = (s[i] == s[j])else:dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])if dp[i][j] and l + 1 > len(ans):ans = s[i:j+1]return ans
1143 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
示例 :
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace",它的长度为 3。
最长公共子序列(Longest Common Subsequence,简称 LCS)是一道比较经典的题目。
首先考虑设计DP数组,对于长度为m和n的字符串s1和s2,有大小为m*n的二维数组DP,DP[i][j]表示:
对于s1[0:i]和s2[0:j],他们的LCS长度为DP[i][j]。
设计好数组,后面的内容就水到渠成了,状态转移方程为:
如果s1[i]==s2[j]
DP[i][j]=DP[i−1][j−1]+1DP[i][j] = DP[i-1][j-1] +1 DP[i][j]=DP[i−1][j−1]+1
如果s1[i]!=s2[j]
DP[i][j]=max(DP[i][j−1],DP[i−1][j])DP[i][j] = max(DP[i][j-1], DP[i-1][j]) DP[i][j]=max(DP[i][j−1],DP[i−1][j])
写成代码:
class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:m = len(text1)n = len(text2)dp = [[0] *(n+1) for _ in range(m+1)]for i in range(1, m+1): # 这里从1开始是为了让dp[i-1][j-1]不溢出,同时提供初值for j in range(1, n+1):if text1[i-1] == text2[j-1]:dp[i][j] =dp[i-1][j-1] + 1else:dp[i][j]=max(dp[i-1][j],dp[i][j-1])return max(max(dp))
还是挺耗费时间的,跑了400+ms。
leetcode刷题记录:算法(九)动态规划相关推荐
- 算法记录 牛客网 leetcode刷题记录
算法记录 & 牛客网 & leetcode刷题记录 解题思路 STL容器 常用算法模板 堆排序 插入排序 快速排序 BFS层序遍历 二叉树 JZ55 二叉树的深度 BST(binary ...
- LeetCode刷题记录8——605. Can Place Flowers(easy)
LeetCode刷题记录8--605. Can Place Flowers(easy) 目录 LeetCode刷题记录8--605. Can Place Flowers(easy) 题目 语言 思路 ...
- wy的leetcode刷题记录_Day66
wy的leetcode刷题记录_Day66 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间:2023-4-10 前言 目录 wy的leetcode刷题记录_Day66 ...
- LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)
LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...
- LeetCode刷题记录14——257. Binary Tree Paths(easy)
LeetCode刷题记录14--257. Binary Tree Paths(easy) 目录 前言 题目 语言 思路 源码 后记 前言 数据结构感觉理论简单,实践起来很困难. 题目 给定一个二叉树, ...
- LeetCode刷题记录13——705. Design HashSet(easy)
LeetCode刷题记录13--705. Design HashSet(easy) 目录 LeetCode刷题记录13--705. Design HashSet(easy) 前言 题目 语言 思路 源 ...
- LeetCode刷题记录12——232. Implement Queue using Stacks(easy)
LeetCode刷题记录12--232. Implement Queue using Stacks(easy) 目录 LeetCode刷题记录12--232. Implement Queue usin ...
- LeetCode刷题记录11——290. Word Pattern(easy)
LeetCode刷题记录11--290. Word Pattern(easy) 目录 LeetCode刷题记录11--290. Word Pattern(easy) 题目 语言 思路 源码 后记 题目 ...
- LeetCode刷题记录10——434. Number of Segments in a String(easy)
LeetCode刷题记录10--434. Number of Segments in a String(easy) 目录 LeetCode刷题记录9--434. Number of Segments ...
- LeetCode刷题记录9——58. Length of Last Word(easy)
LeetCode刷题记录9--58. Length of Last Word(easy) 目录 LeetCode刷题记录9--58. Length of Last Word(easy) 题目 语言 思 ...
最新文章
- mysql从某表中查询数据插入到另一表的处理
- EOS 消息设计(3)并行处理之状态评估
- arcgis与python_Arcgis-ModelBuilder和Python学习
- VS2008非托管c++访问webservice服务(以WeatherWS 天气服务 为例)
- leetcode107. 二叉树的层次遍历 II
- [转载] Java中日期格式转换
- kd树介绍(KNN算法引出)
- vue让元素固定_vue 监听dom元素的滚动事件 实现某元素吸顶或者固定位置显示
- sql server高可用_SQL Server始终在线可用性组采访问题与解答
- sysbench压测cpu,io,memory,threads,mutex
- win10怎么把c盘锁住_Win10 C盘怎么瘦身?史上最强C盘清理方案
- 计算机英语词汇电子书,计算机英语词汇-打印版.pdf
- 开服侠如何修改服务器头像,王者荣耀怎么更换头像 修改头像攻略
- Android——Timer停不下来的解决方法
- android6最新版本,安卓版“AirDrop”发布,安卓6版本以上都能用!
- Python实现的双目相机标定系统
- 用python计算100以内所有奇数的和_python怎样求1到100的奇数和
- 阿里云服务器没有公网IP
- Geometry-guided Kernel Transformer ——GKT代码复现
- 吴军的谷歌方法论|周末放送|Google的个人英雄主义和群众路线