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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 算法学习笔记——动态规划:戳气球 -> 正文阅读

[数据结构与算法]算法学习笔记——动态规划:戳气球

LeetCode 312. 戳气球
数组 nums 中,保存了每个气球上的数字,戳破一个气球,得分是nums[i - 1] * nums[i] * nums[i + 1](若越界,认为两个边界上有数值为1的虚拟气球)
可以按照不同顺序戳破气球,问所能得到的最高分数
如nums = [3,1,5,8],返回167([3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> [])

暴力解法:回溯

涉及求最值,一定要穷举所有可能结果,然后比较得出最值
暴力穷举就是回溯,若能找到独立子问题,更聪明的穷举就是动态规划

回溯思路:穷举戳破气球的所有不同顺序,这就相当于“全排列”问题,用数组代表气球,并动态更新数组的值,从而实时模拟气球的情况,注意每次做选择后还原现场

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        maxScore = 0
        def backtrack(arr, score):
        	# arr保存当前气球的情况
            nonlocal maxScore
            if not arr:# 戳完了所有气球
                maxScore = max(maxScore, score)
                return
            for i in range(len(arr)):
                l = 1 if i == 0 else arr[i - 1]
                r = 1 if i == len(arr) - 1 else arr[i + 1]
                point = l * r * arr[i]
                # 尝试戳第i个气球
                balloon = arr.pop(i)
                backtrack(arr, score + point)
                # 还原现场
                arr.insert(i, balloon)
        backtrack(nums, 0)
        return maxScore

动态规划

思路:

  1. 动态规划要求子问题独立,因此我们需要转化dp的定义,构造独立的子问题
  2. 怎样找互不关联的子问题呢?
    可以利用逆向思维求解:对所有气球,考虑最后戳破哪一个气球得分最高
    如果最后戳破气球i,又构造出了两个独立子问题:对于气球i左边的那些气球,最后戳破哪个分最高/对于气球i右边的那些气球,最后戳破哪个分最高
    在这里插入图片描述
  3. 状态:当前考虑的这些气球的左右边界
    选择:对于这些气球,最后戳破哪一个,总得分最高
  4. 为了代码统一,先将左右两侧的“虚拟气球”加到数组中
    数组nums的下标范围变为0~(L=n+1)(n为原来的总气球数量)
  5. dp数组定义:dp[i][j]表示戳破区间(i,j)内(不包括ij)的气球的最高分,则我们要求的答案就是dp[0][L-1]
    每次尝试不同的气球作为最后戳破的气球(同时分出两个子问题dp[0][i]dp[i][L-1]),并求最大值
  6. 状态转移方程:假设最后戳破了气球k,那么dp[i][j]=max(dp[i][j],nums[i]*nums[k]*nums[j]+dp[i][k]+dp[k][j])
    理解:对于区间(i,j),最后戳破气球k时,其两边一定是气球i和j

实现:
根据base case和答案位置dp[0][L-1]可知,求解顺序从下往上从左往右
iL-3开始,ji+2开始,ki+1开始
在这里插入图片描述

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        # 首尾加上“虚拟气球”,之后注意气球0/气球n+1不可戳破
        nums.insert(0, 1)
        nums.append(1)
        # 气球总数
        L = len(nums)  # 总气球数,气球0/气球L-1不可戳破

        # dp[i][j]表示戳破区间(i,j)内(不包括i、j)的气球的最高分,则我们要求的答案就是dp[0][L-1]
        dp = [[0 for _ in range(L)] for _ in range(L)]
        # base case :i>=j时/j==i+1时,没有气球可以戳破,得分0

        for i in range(L - 3, -1, -1):
            for j in range(i + 2, L):
                for k in range(i + 1, j):
                    # 对于区间(i,j)内的气球,最后戳破气球k
                    # 得分=最后戳破气球得分+左区间得分+右区间得分
                    dp[i][j] = max(dp[i][j], nums[i] * nums[k] * nums[j] + dp[i][k] + dp[k][j])
        return dp[0][L - 1]
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:09:52  更:2022-07-20 19:12:01 
 
开发: 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:13:56-

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