动态规划(Dynamic Programming,DP)

根据百度百科上的定义:

动态规划是求解决策过程最优化的过程

然后各个博客里对动态规划的描述为:

将需要求解的大问题,分解为一个个的小问题,并在计算过程中保存每个小问题的结果以避免重复计算。

动态规划是一种以空间换时间的技术。我看了几个例子,感觉动态规划其实是递归的反推:
递归: 从要求的的问题(顶层)开始,一层一层递归到出口条件,然后再逐层返回
动态规划:出口条件开始 ,逐层上升到要求解的问题。

动态规划感觉是迄今为止最难理解的一种算法了,我找了些资料看,感觉还是没有领会到精髓,做题熟悉吧。

70 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

爬到第n阶有两种可能

  1. 现在站在第n-2阶,再一次性爬两阶;
  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 最长回文子串

一开始看到这道题的时候,想用滑动窗口解,因为回文串存在两种情况:

  1. aba
  2. 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刷题记录:算法(九)动态规划相关推荐

  1. 算法记录 牛客网 leetcode刷题记录

    算法记录 & 牛客网 & leetcode刷题记录 解题思路 STL容器 常用算法模板 堆排序 插入排序 快速排序 BFS层序遍历 二叉树 JZ55 二叉树的深度 BST(binary ...

  2. LeetCode刷题记录8——605. Can Place Flowers(easy)

    LeetCode刷题记录8--605. Can Place Flowers(easy) 目录 LeetCode刷题记录8--605. Can Place Flowers(easy) 题目 语言 思路 ...

  3. wy的leetcode刷题记录_Day66

    wy的leetcode刷题记录_Day66 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间:2023-4-10 前言 目录 wy的leetcode刷题记录_Day66 ...

  4. LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)

    LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...

  5. LeetCode刷题记录14——257. Binary Tree Paths(easy)

    LeetCode刷题记录14--257. Binary Tree Paths(easy) 目录 前言 题目 语言 思路 源码 后记 前言 数据结构感觉理论简单,实践起来很困难. 题目 给定一个二叉树, ...

  6. LeetCode刷题记录13——705. Design HashSet(easy)

    LeetCode刷题记录13--705. Design HashSet(easy) 目录 LeetCode刷题记录13--705. Design HashSet(easy) 前言 题目 语言 思路 源 ...

  7. LeetCode刷题记录12——232. Implement Queue using Stacks(easy)

    LeetCode刷题记录12--232. Implement Queue using Stacks(easy) 目录 LeetCode刷题记录12--232. Implement Queue usin ...

  8. LeetCode刷题记录11——290. Word Pattern(easy)

    LeetCode刷题记录11--290. Word Pattern(easy) 目录 LeetCode刷题记录11--290. Word Pattern(easy) 题目 语言 思路 源码 后记 题目 ...

  9. 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 ...

  10. LeetCode刷题记录9——58. Length of Last Word(easy)

    LeetCode刷题记录9--58. Length of Last Word(easy) 目录 LeetCode刷题记录9--58. Length of Last Word(easy) 题目 语言 思 ...

最新文章

  1. mysql从某表中查询数据插入到另一表的处理
  2. EOS 消息设计(3)并行处理之状态评估
  3. arcgis与python_Arcgis-ModelBuilder和Python学习
  4. VS2008非托管c++访问webservice服务(以WeatherWS 天气服务 为例)
  5. leetcode107. 二叉树的层次遍历 II
  6. [转载] Java中日期格式转换
  7. kd树介绍(KNN算法引出)
  8. vue让元素固定_vue 监听dom元素的滚动事件 实现某元素吸顶或者固定位置显示
  9. sql server高可用_SQL Server始终在线可用性组采访问题与解答
  10. sysbench压测cpu,io,memory,threads,mutex
  11. win10怎么把c盘锁住_Win10 C盘怎么瘦身?史上最强C盘清理方案
  12. 计算机英语词汇电子书,计算机英语词汇-打印版.pdf
  13. 开服侠如何修改服务器头像,王者荣耀怎么更换头像 修改头像攻略
  14. Android——Timer停不下来的解决方法
  15. android6最新版本,安卓版“AirDrop”发布,安卓6版本以上都能用!
  16. Python实现的双目相机标定系统
  17. 用python计算100以内所有奇数的和_python怎样求1到100的奇数和
  18. 阿里云服务器没有公网IP
  19. Geometry-guided Kernel Transformer ——GKT代码复现
  20. 吴军的谷歌方法论|周末放送|Google的个人英雄主义和群众路线

热门文章

  1. MySQL创建及管理数据库
  2. AI 时代的学习方式: 和文档对话
  3. 如何灵活的实现告警的通知?
  4. 笔记本电脑自带录屏在哪?一步教您找到
  5. 数字图像处理第六章 ——彩色图像处理(下)
  6. 文献阅读-区块链技术与应用前瞻综述
  7. 在CentOS Linux release 7.5安装8.0MySQL详细教程
  8. Dubbo学习-注册中心
  9. 用Grub4Dos硬盘安装Linux
  10. 软件测试人员必备Linux命令(初,中,高级)