记一次动态规划的采坑之旅, 741摘樱桃 https://leetcode.cn/problems/cherry-pickup/description/

本文主要是介绍记一次动态规划的采坑之旅, 741摘樱桃 https://leetcode.cn/problems/cherry-pickup/description/,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首次看题目时,发现是困难。立马想到了,动态规划。

再看题目, 摘樱桃,还要返回摘两次,求摘最多的樱桃。

大脑第一反应就是:

先使用动态规划,找到 0 0 到 n-1 n-1处走过的最大樱桃, 并记录路径path。

然后根据路径path,将摘过的樱桃置为0,表示已经被摘过了。 然后再次摘樱桃。

两次摘过的樱桃之和就是目标的结果。

嗯,应该是,那就开写。

func cherryPickup(grid [][]int) int {ans := 0n := len(grid)dp := make([][]int, 0)for i := 0; i < n; i++ {dp = append(dp, make([]int, n))}// 1 表示上一个路径是 上// 2 表示上一个路径是 左path := make([][]int, 0)for i := 0; i < n; i++ {path = append(path, make([]int, n))}// 记录首次dp的轨迹,开始第一次摘for i := 0; i < len(grid); i++ {for j := 0; j < len(grid[0]); j++ {if i == 0 && j == 0 {dp[0][0] = grid[0][0]continue}if grid[i][j] == -1 {dp[i][j] = -1continue}if (i - 1 < 0 || grid[i-1][j] == -1 || dp[i-1][j] == -1) && (j - 1 < 0 || grid[i][j-1] == -1 || dp[i][j-1] == -1) {dp[i][j] = -1continue}if i - 1 < 0 || grid[i-1][j] == -1 || dp[i-1][j] == -1 {dp[i][j] = dp[i][j-1] + grid[i][j]path[i][j] = 2continue}if j - 1 < 0 || grid[i][j-1] == -1 || dp[i][j-1] == -1 {dp[i][j] = dp[i-1][j] + grid[i][j]path[i][j] = 1continue}if dp[i][j-1] > dp[i-1][j] {path[i][j] = 2dp[i][j] = dp[i][j-1] + grid[i][j]} else {path[i][j] = 1dp[i][j] = dp[i-1][j] + grid[i][j]}}}ans += dp[n-1][n-1]if ans == -1 {return 0}// 回溯路径, 清理已经被摘过的樱桃ii, jj := n-1, n-1for path[ii][jj] != 0 {grid[ii][jj] = 0if path[ii][jj] == 1 {ii--} else {jj--}}// 第二次摘樱桃grid[0][0] = 0dp = make([][]int, 0)for i := 0; i < n; i++ {dp = append(dp, make([]int, n))}for i := 0; i < len(grid); i++ {for j := 0; j < len(grid[0]); j++ {if i == 0 && j == 0 {dp[0][0] = grid[0][0]continue}if grid[i][j] == -1 {dp[i][j] = -1continue}if (i - 1 < 0 || grid[i-1][j] == -1 || dp[i-1][j] == -1) && (j - 1 < 0 || grid[i][j-1] == -1 || dp[i][j-1] == -1) {dp[i][j] = -1continue}if i - 1 < 0 || grid[i-1][j] == -1 || dp[i-1][j] == -1 {dp[i][j] = dp[i][j-1] + grid[i][j]path[i][j] = 2continue}if j - 1 < 0 || grid[i][j-1] == -1 || dp[i][j-1] == -1 {dp[i][j] = dp[i-1][j] + grid[i][j]path[i][j] = 1continue}if dp[i][j-1] > dp[i-1][j] {path[i][j] = 2dp[i][j] = dp[i][j-1] + grid[i][j]} else {path[i][j] = 1dp[i][j] = dp[i-1][j] + grid[i][j]}}}// 将两次摘的樱桃数相加return ans + dp[n-1][n-1]
}

最后发现通过 53/59 , 差一点点点点。 其实差很多。

通过研究这个未通过的案例, 发现我虽然2次摘樱桃都是最大值, 但并不能证明最终采摘的樱桃数是最大的。

最后瞄了一眼答案, 来回摘2次樱桃数最多,又不能重复摘, 那找两个人同时摘不就好了吗。 

附上leetcode标准答案

func cherryPickup(grid [][]int) int {n := len(grid)f := make([][][]int, n*2-1)for i := range f {f[i] = make([][]int, n)for j := range f[i] {f[i][j] = make([]int, n)for k := range f[i][j] {f[i][j][k] = math.MinInt32}}}f[0][0][0] = grid[0][0]for k := 1; k < n*2-1; k++ {for x1 := max(k-n+1, 0); x1 <= min(k, n-1); x1++ {y1 := k - x1if grid[x1][y1] == -1 {continue}for x2 := x1; x2 <= min(k, n-1); x2++ {y2 := k - x2if grid[x2][y2] == -1 {continue}res := f[k-1][x1][x2] // 都往右if x1 > 0 {res = max(res, f[k-1][x1-1][x2]) // 往下,往右}if x2 > 0 {res = max(res, f[k-1][x1][x2-1]) // 往右,往下}if x1 > 0 && x2 > 0 {res = max(res, f[k-1][x1-1][x2-1]) // 都往下}res += grid[x1][y1]if x2 != x1 { // 避免重复摘同一个樱桃res += grid[x2][y2]}f[k][x1][x2] = res}}}return max(f[n*2-2][n-1][n-1], 0)
}func min(a, b int) int {if a > b {return b}return a
}func max(a, b int) int {if b > a {return b}return a
}作者:力扣官方题解
链接:https://leetcode.cn/problems/cherry-pickup/solutions/1656418/zhai-ying-tao-by-leetcode-solution-1h3k/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这篇关于记一次动态规划的采坑之旅, 741摘樱桃 https://leetcode.cn/problems/cherry-pickup/description/的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/964928

相关文章

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

电脑多久清理一次灰尘合? 合理清理电脑上灰尘的科普文

《电脑多久清理一次灰尘合?合理清理电脑上灰尘的科普文》聊起电脑清理灰尘这个话题,我可有不少话要说,你知道吗,电脑就像个勤劳的工人,每天不停地为我们服务,但时间一长,它也会“出汗”——也就是积累灰尘,... 灰尘的堆积几乎是所有电脑用户面临的问题。无论你的房间有多干净,或者你的电脑是否安装了灰尘过滤器,灰尘都

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同