算法详解-动态规划-如何用智慧打败暴力

这篇具有很好参考价值的文章主要介绍了算法详解-动态规划-如何用智慧打败暴力。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


什么是动态规划?

😎🥳😎🤠😮🤖🙈💭🍳🍱
动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划算法是一种高效的求解最优化问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,可以通过记忆化存储子问题的解,避免重复计算,提高效率。

动态规划的核心思想是拆分子问题,记住过往,减少重复计算。

动态规划一般需要找到一个递推关系式,根据已知的边界条件和子问题的解,推导出原问题的解。

动态规划的应用

动态规划在实际中的应用极其广泛,包括工程技术、经济、工业生产、军事以及自动化控制等领域,并在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题等中取得了显著的效果。

如何求解动态规划?

一般来说,求解动态规划问题的思路步骤如下:

  • 分析问题,确定是否具有最优子结构和重叠子问题的性质,即是否可以用动态规划来求解。
  • 定义状态,即用一个或多个变量来描述问题的子问题。
  • 找出状态转移方程,即用递推关系式来表示不同状态之间的联系。
  • 确定边界条件,即初始状态和终止状态的值。
  • 选择合适的存储结构,如数组、哈希表等,来保存子问题的解,并按照一定的顺序进行计算和填表。
  • 根据存储结构中的结果,得出原问题的解,有时还需要进行回溯或者路径记录。

用刷题感受一下

🦞🦐🦀🦑🦪

初级

斐波那契数列

题目描述

第一二项为1,后面每项等于前两项和,求第n项

解题思路

每一项为前两项和,则dp[i]=dp[i-1]+dp[i-2],边界条件为dp[0]=1,dp[1]=1

Python

def fib(n):
    dp=[0]*n
    dp[0],dp[1]=1,1
    for i in range(2,n):
        dp[i]=dp[i-1]+dp[i-2]
    return dp[n-1]

print(fib(50))

爬楼梯

题目描述

爬楼梯:给定一个整数 n ,表示楼梯的阶数,每次可以爬 1 或 2 阶,求有多少种不同的方法可以爬到楼顶。

解题思路

这个问题可以用动态规划来求解,具体方法是定义一个数组 d ,其中 d [i] 表示爬到第 i 阶楼梯的方法数,那么 d [i] = d [i-1] + d [i-2] ,即爬到第 i 阶可以从第 i-1 阶爬 1 阶或者从第 i-2 阶爬 2 阶得到。

边界条件是 d [0] = 1 ,d 1 = 1

Python

def climbStairs( n: int) -> int:
        # 初始化数组
        d = [0] * (n + 1)
        # 边界条件
        d[0] = 1
        d[1] = 1
        # 状态转移方程
        for i in range(2, n + 1):
            d[i] = d[i - 1] + d[i - 2]
        # 返回结果
        return d[n]

print(climbStairs(6))
print(climbStairs(7))

最长上升子序列

题目描述

给定一个无序的整数数组,找到其中最长上升子序列的长度。

解题思路

这个问题也可以用动态规划来求解,具体方法是定义一个数组 dp ,其中 dp [i] 表示以 nums [i] 结尾的最长上升子序列的长度,那么 dp [i] = max (dp [j]) + 1 ,其中 j < i 且 nums [j] < nums [i] ,即在所有小于 i 的下标 j 中找到一个使得 nums [j] < nums [i] 的最大 dp 值,并加上自身长度 1 。

边界条件是 dp 数组全初始化为 1 。

Python

def lengthOfLIS(nums:list) -> int:
        # 初始化数组
        dp = [1] * len(nums)
        # 状态转移方程
        for i in range(1, len(nums)):
            for j in range(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j]+1)
        # 返回结果
        return max(dp)

l=[1,2,3,4,6,5,8,7,8]
print(lengthOfLIS(l))

不同路径

题目描述

给定一个 m x n 的网格,从左上角开始,每次只能向右或者向下移动一步,到达右下角有多少种不同的路径。

解题思路

这个问题可以用动态规划来求解,具体方法是定义一个二维数组 dp ,其中 dp [i] [j] 表示从左上角到达 (i, j) 位置的不同路径数,那么 dp [i] [j] = dp [i-1] [j] + dp [i] [j-1] ,即到达 (i, j) 位置可以从上方或者左方移动一步得到。

边界条件是第一行和第一列都只有一种路径,即 dp [0] [] = 1 和 dp [] [0] = 1

Python

def uniquePaths(m: int, n: int) -> int:
        # 初始化二维数组
        dp = [[0 for _ in range(n)] for _ in range(m)]
        # 边界条件
        for i in range(m):
            dp[i][0] = 1
        for j in range(n):
            dp[0][j] = 1
        # 状态转移方程
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        # 返回结果
        return dp[m-1][n-1]

print(uniquePaths(2,2))
print(uniquePaths(3,20))

最小路径和

题目描述

最小路径和:给定一个 m x n 的网格,其中每个格子填写了非负整数,从左上角开始,每次只能向右或者向下移动一步,找到一条到达右下角的路径,使得路径上经过的数字之和最小。

解题思路

这个问题也可以用动态规划来求解,具体方法是定义一个二维数组 dp ,其中 dp [i] [j] 表示从左上角到达 (i, j) 位置的最小路径和,那么 dp [i] [j] = min (dp [i-1][j],dp[i][j-1]) + grid[i][j], 即到达 (i,j) 位置可以从上方或者左方移动一步得到,并加上当前格子的数字。

边界条件是第一行和第一列需要累加前面的数字之和。

Python

def minPathSum(grid) -> int:
        # 初始化二维数组
        m = len(grid)
        n = len(grid[0])
        dp = [[0 for _ in range(n)] for _ in range(m)]
        # 边界条件
        dp[0][0]=grid[0][0]
        for i in range(1,m):
            dp[i][0]=dp[i-1][0]+grid[i][0]
        for j in range(1,n):
            dp[0][j]=dp[0][j-1]+grid[0][j]
        # 状态转移方程
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
        # 返回结果
        return dp[m-1][n-1]

l=[
     [1,2,3,4,5,6,7],
     [1,2,3,4,5,6,7],
     [1,2,3,4,5,6,7],
     [1,2,3,4,5,6,7],
     [1,2,3,4,5,6,7],
]
print(minPathSum(l))

最长公共子序列

题目描述

最长公共子序列:给定两个字符串 text1 和 text2 ,返回这两个字符串的最长公共子序列(LCS)的长度。一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。如果不存在公共子序列,返回 0 。

解题思路

这个问题可以用动态规划来求解,具体方法是定义一个二维数组 dp ,其中 dp [i] [j] 表示 text1[0:i] 和 text2[0:j] 的最长公共子序列长度,那么 dp [i] [j] 有以下两种情况:
如果 text1[i-1] == text2[j-1] ,则 dp [i] [j] = dp [i-1][j-1]+1 ,即在前面最长公共子序列基础上加上当前相同字符。
如果 text1[i-1] != text2[j-1] ,则 dp [i][j]=max(dp[i-1][j],dp[i][j-1]) ,即取前面两种可能中较大者。

边界条件是第一行和第一列都为 0 ,因为空串与任何串没有公共子序列。


持续更新中,遗忘请戳戳~~~

Python


斐波那契数列

题目描述

解题思路

C++


Python


斐波那契数列

题目描述

解题思路

C++


Python


斐波那契数列

题目描述

解题思路

C++


Python


斐波那契数列

题目描述

解题思路

C++


Python



动态规划的优缺点

动态规划有以下一些优缺点:

优点:

  • 动态规划可以有效地解决一些具有重叠子问题和最优子结构的问题,避免了重复计算,提高了效率。
  • 动态规划可以将复杂的问题分解为相对简单的子问题,降低了问题的难度,便于理解和求解。
  • 动态规划可以在求解最优值的同时,还能得到最优解的具体方案,方便进行分析和应用。

缺点:

  • 动态规划需要存储大量的中间结果,可能会占用较多的空间。
  • 动态规划需要找到合适的状态定义和状态转移方程,这可能不是很容易做到,需要一定的技巧和经验。
  • 动态规划对于一些没有明显最优子结构或者重叠子问题的问题,并不适用,可能会得到错误或者非最优的结果。

总结

🐋 🐬 🐶 🐳 🐰 🦀☝️ ⭐ 👉 👀

如果你对这篇文章感兴趣,欢迎在评论区留言,分享你的想法和建议。如果你喜欢我的博客,请记得点赞、收藏和关注我,我会持续更新更多有用的网页技巧和教程。谢谢大家!


更多宝藏

🍇🍉🍊🍏🍋🍅🥝🥥🫒🫕🥗
项目仓库看这里🤗:
https://github.com/w-x-x-w
https://gitee.com/w-_-x
博客文章看这里🤭:
https://blog.csdn.net/weixin_62650212
视频推送看这里🤤:
https://space.bilibili.com/1909782963文章来源地址https://www.toymoban.com/news/detail-417005.html

到了这里,关于算法详解-动态规划-如何用智慧打败暴力的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法8.从暴力递归到动态规划1

    目前感觉,背包问题和货币数组问题本质相同,货币的与dp相关的三种代码写完了,快复习不完了,背包暂时先不写了,回头再写,补充,再总结,结合那个C++大神的文章再弄。 目前来讲,我接触到的背包问题有四种分别是01背包、完全背包、多重背包、以及部分背包。背包

    2024年02月07日
    浏览(37)
  • 暴力递归到动态规划(三)

    ⭐️ 前言 ⭐️ 本篇文章是从暴力递归到动态规划的第三章。 🍉 欢迎点赞 👍 收藏 ⭐ 留言评论 📝 私信必回哟 😁 🍉 博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 🍉 博客中涉及源码及博主日常练习代码均已上传GitHub 题目: 给定一个二维数组mat

    2024年02月09日
    浏览(38)
  • 暴力递归到动态规划(四)

    ⭐️ 前言 ⭐️ 本篇文章是从暴力递归到动态规划篇目的最后一篇文章,包含了几道题目还有最终的大总结,相信这篇文章能让各位读者对动态规划有更深一步的了解。 🍉 欢迎点赞 👍 收藏 ⭐ 留言评论 📝 私信必回哟 😁 🍉 博主将持续更新学习记录收获,友友们有任何问

    2024年02月08日
    浏览(42)
  • 一篇文章带你搞懂动态规划(由暴力递归到动态规划)

    ”动态规划“ 的过程相当于 记忆化搜索 , 即在普通 递归 的过程中用二维数组进行记忆化存储一些状态结果, 从而避免重复的计算(剪枝)。 举一个简单的例子:在 递归法 求解 斐波那契 数列的过程中, 就进行了多次的 重复计算 , 而动态规划相当于是对已经计算的状态

    2024年02月20日
    浏览(55)
  • 左程云 Java 笔记--暴力递归--动态规划

    暴力递归就是尝试 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程, 4,不记录每一个子问题的解 打印n层汉诺塔从最左边移动到最右边的全部过程 打印一个字符串的全部子序列,包

    2023年04月08日
    浏览(51)
  • 最大正方形(力扣)暴力 + 动态规划 JAVA

    在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。 示例 1: 输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]] 输出:4 示例 2: 输入:m

    2024年02月15日
    浏览(62)
  • ★动态规划(DP算法)详解

    什么是动态规划:动态规划_百度百科 内容太多了不作介绍,重点部分是无后效性,重叠子问题,最优子结构。 问S-P1和S-P2有多少种路径数,毫无疑问可以先从S开始深搜两次,S-P1和S-P2找出所有路径数,但是当这个图足够大,那就会超时。 动态规划旨在用 空间换时间 ,我们

    2024年02月04日
    浏览(50)
  • 题解 | #上台阶#C++暴力动态规划解法,非递归

    25届想找实习求看看简历 英伟达笔试 Nvidia24秋招 英伟达嵌入式软件工程师笔试 9-26 2022-08-17-nvidia实习 我发现算法岗也不很难进啊(深度学习) 我发现算法岗也不很难进啊(深度学习) 顺丰科技 1.30校招实习招聘信息汇总 2024春招汇总 『 哨哥的校园招聘周报 』02/05 - 02/18 深圳银河创

    2024年02月21日
    浏览(38)
  • 爬楼梯问题-从暴力递归到动态规划(java)

    一个总共N 阶的楼梯(N 0) 每次只能上一阶或者两阶。问总共有多少种爬楼方式。 示例1: N = 1, 一步上去了,返回1. 示例2: N = 2时。 可以第一次上一阶,再上一阶,这是一种方式, 也可以一次直接上两阶,这也是一种方式, 返回 2; 示例3: N = 3: 可以选择, 1 1 1, 1

    2024年02月10日
    浏览(36)
  • 【LeetCode:72. 编辑距离 | 暴力递归=>记忆化搜索=>动态规划 】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月06日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包