记一次动态规划的采坑之旅, 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

相关文章

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

springboot项目如何开启https服务

《springboot项目如何开启https服务》:本文主要介绍springboot项目如何开启https服务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录springboot项目开启https服务1. 生成SSL证书密钥库使用keytool生成自签名证书将

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu