IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 动态规划学习(持续更新) -> 正文阅读

[数据结构与算法]动态规划学习(持续更新)

本篇博文主要记录动态规划DP这一块的学习。

印章(蓝桥杯6.27)

问题描述:共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。(1≤n,m≤20)
输入格式:一行两个正整数n和m
输出格式:一个实数P表示答案,保留4位小数。

思考1:
概率论?!分类讨论
1)当m<n时,集齐的概率为0
2)当m>n时,买的m张印章,每张有n种可能,分母:n的m次方;分子:(C_m^n) * (C_n m-n)(m张印章中,有n张是图案不同的,剩下的m-n张随意)。

思考2:
动态规划解题步骤:

1)设置状态,即数组
dp[i][j] = 印章数目为i、集齐j种印章的概率
dp[1][1] = 1
dp[i][1] = (1/n)^(i-1)
i < j时,dp = 0

2)确定状态转移方程
找状态之间的关系,从手里有(i-1)枚印章到 i 枚印章时,有两种情况,第一种,拿到的这枚印章种类手里已经有了,此时 dp[i][j] 表示手里已经有 j 种印章了,因此上个状态也只有 j 种印章,即 dp[i-1][j] 。dp[i][j] = dp[i-1][j] * j/n;第二种,拿到的这枚印章种类手里还没有,所以上个状态表示为dp[i-1][j-1],一共有n种印章,前面已经取了(j-1)种,而现在取的和前面没有重复,因此取的是n-(j-1)中的其中一个。

3)代码实现

n,m = map(int,input().split())
dp = [[0 for i in range(n+1)]for i in range(m+1)]
for i in range(1,m+1):
    for j in range(1,n+1):
        if (i < j):
            dp[i][j] = 0
        elif (j == 1):
            dp[i][j] = (1/n)**(i-1)
        else:
            dp[i][j] = (dp[i-1][j])*(j*1.0/n) + (dp[i-1][j-1])*((n-j+1)*1.0/n)
print("%.4f"%(dp[m][n]))   

拿金币(蓝桥杯6.28)

问题描述:有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式:第一行输入一个正整数n。以下n行描述该方格。金币数保证是不超过1000的正整数。
输出格式:最多能拿金币数量。

思考1:
n*n的方格应该用一个数组表示,dp[i][j]表示i行j列的金币数量,想要求出能拿金币最多的数量,每次移动做选择的时候,比较右边还是下边的金币数量大,哪边大就往哪边移动,直到不能移动为止(没有向右也没有向下的选择,即边界处)

思考2:
状态转移方程
dp[i][j] = max((dp[i][j-1]+dp[i][j]),(dp[i-1][j]+dp[i][j]))

代码

n = int(input())
rect = []

for i in range(n):
    rect.append(list(map(int, input().split())))
    
#将边界的数单独算出来    
for i in range(1,n):
    rect[0][i] =rect[0][i] + rect[0][i-1]
    
for i in range(1,n):
    rect[i][0] = rect[i][0] + rect[i-1][0]
    
for i in range(1,n):
    for j in range(1,n):
        rect[i][j] = max(rect[i][j-1],rect[i-1][j]) + rect[i][j]
                
print(rect[-1][-1])

最长回文子串(力扣6.29)

在这里插入图片描述
思考1:
1)关于判断是否为回文数,之前写过博客,可直接s==s[::-1]
2)字串可通过双循环得到
3)回文字串的长度最大!?
但这种判断肯定复杂度很高,而且这道题是动态规划那一p的,所以这个思路应该不太对。

思考2:
1)s[0…j]是回文子串则s[1…j-1]必定是回文子串,而且s[0]==s[j]
2)dp[i][j]为“s[i…j]是否为回文字符串”,如果是回文字符串,则dp[i][j]=true,且dp[i][j]=dp[i+1][j-1] && s[i]==s[j](状态转移方程)
3)问题边界,有1个字符时,dp=true;有两个字符,即i+1=j时,如果s[i]==s[j],则dp[i][j]=true

代码如下:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n < 2:
            return s
        
        max_len = 1
        begin = 0
        # dp[i][j] 表示 s[i..j] 是否是回文串
        dp = [[False] * n for _ in range(n)]
        for i in range(n):
            dp[i][i] = True
        
        # 递推开始
        # 先枚举子串长度
        for L in range(2, n + 1):
            # 枚举左边界,左边界的上限设置可以宽松一些
            for i in range(n):
                # 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                j = L + i - 1
                # 如果右边界越界,就可以退出当前循环
                if j >= n:
                    break
                    
                if s[i] != s[j]:
                    dp[i][j] = False 
                else:
                    if j - i < 3:
                        dp[i][j] = True
                    else:
                        dp[i][j] = dp[i + 1][j - 1]
                
                # 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if dp[i][j] and j - i + 1 > max_len:
                    max_len = j - i + 1
                    begin = i
        return s[begin:begin + max_len]

最大子数组和(力扣6.30)

在这里插入图片描述
思考1:
dp[i][j]表示nums中从 i 到 j 位置的和。
dp[i][i]表示nums本身
状态转移方程:
i < j 时,dp[i][j] = dp[i][j-1] + nums[j]
返回dp中最大的值。

思考2:
二维数组表示最大值反而复杂了,一维数组即可。
dp[i]:表示以 nums[i] 结尾的连续子数组的最大和。
如果dp[i - 1] > 0,那么可以把nums[i]直接接在dp[i - 1]表示的那个数组的后面,得到和更大的连续子数组;
如果dp[i - 1] <= 0,那么nums[i]加上前面的数dp[i - 1]以后值不会变大。此时单独的一个nums[i]的值,就是dp[i]。

代码:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0] * n
        dp[0] = nums[0]

        for i in range(1,n):
            dp[i] = max(dp[i-1]+nums[i],nums[i])

        return max(dp)

爬楼梯(力扣7.1)

在这里插入图片描述
思考1:
设置状态和边界条件:
dp[i]表示到i阶有dp[i]种方法;dp[1]=1,dp[2] = 2,dp[3]=3

状态转移方程:
dp[i] = dp[i-1] + dp[i-2]

class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [0] * n
        dp[0] = 1
        ways = 0
        if n == 1:
            ways = 1
        elif n == 2:
            ways = 2
        else: 
            dp[1] = 2
            for i in range(2,n):
                dp[i] = dp[i-1] + dp[i-2]
            ways = dp[n-1]
        return ways

杨辉三角(7.2)

在这里插入图片描述
思考:
二维数组dp[i][j]表示第i行第j列的数字,每行的第一个和最后一个数字都是1。
状态转移方程:
当j=0或i时,dp[][]=1
其他情况下,dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
二维数组的创建?!

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        dp = [[0] * i for i in range(1,numRows+1)]

        dp[0][0] = 1

        if numRows==1:
            dp = [[1]]
    
        elif numRows==2:
            dp = [[1],[1,1]]
    
        else:
            for i in range(numRows):
                for j in range(i+1):
                    if (j==0)or(j==i):
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
        return dp

官方答案:

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        ret = list()
        for i in range(numRows):
            row = list()
            for j in range(0, i + 1):
                if j == 0 or j == i:
                    row.append(1)
                else:
                    row.append(ret[i - 1][j] + ret[i - 1][j - 1])
            ret.append(row)
        return ret
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 11:03:35  更:2022-07-03 11:05:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:51:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码