In a N x N grid representing a field of cherries, each cell is one of three possible integers.

  • 0 means the cell is empty, so you can pass through;
  • 1 means the cell contains a cherry, that you can pick up and pass through;
  • -1 means the cell contains a thorn that blocks your way.

Your task is to collect maximum number of cherries possible by following the rules below:

  • Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid path cells (cells with value 0 or 1);
  • After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells;
  • When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0);
  • If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected.

Example 1:

Input: grid =
[[0, 1, -1],
[1, 0, -1],
[1, 1, 1]]
Output: 5
Explanation:
The player started at (0, 0) and went down, down, right right to reach (2, 2).
4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]].
Then, the player went left, up, up, left to return home, picking up one more cherry.
The total number of cherries picked up is 5, and this is the maximum possible.

Note:

  • grid is an N by N 2D array, with 1 <= N <= 50.
  • Each grid[i][j] is an integer in the set {-1, 0, 1}.
  • It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1.

64. Minimum Path Sum 类似,但这个题还要返回到起点,而且捡过的位置由1变为0,如果分别计算去时和回来时的路径,就要把捡过的变为0,会很麻烦。

解法:DP, 同时计算去和回的dp值。

参考:Grandyang

https://leetcode.com/problems/cherry-pickup/discuss/109903/Step-by-step-guidance-of-the-O(N3)-time-and-O(N2)-space-solution

Java:

public int cherryPickup(int[][] grid) {
int N = grid.length, M = (N << 1) - 1;
int[][] dp = new int[N][N];
dp[0][0] = grid[0][0]; for (int n = 1; n < M; n++) {
for (int i = N - 1; i >= 0; i--) {
for (int p = N - 1; p >= 0; p--) {
int j = n - i, q = n - p; if (j < 0 || j >= N || q < 0 || q >= N || grid[i][j] < 0 || grid[p][q] < 0) {
dp[i][p] = -1;
continue;
} if (i > 0) dp[i][p] = Math.max(dp[i][p], dp[i - 1][p]);
if (p > 0) dp[i][p] = Math.max(dp[i][p], dp[i][p - 1]);
if (i > 0 && p > 0) dp[i][p] = Math.max(dp[i][p], dp[i - 1][p - 1]); if (dp[i][p] >= 0) dp[i][p] += grid[i][j] + (i != p ? grid[p][q] : 0)
}
}
} return Math.max(dp[N - 1][N - 1], 0);
}

Python:

class Solution(object):
def cherryPickup(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
# dp holds the max # of cherries two k-length paths can pickup.
# The two k-length paths arrive at (i, k - i) and (j, k - j),
# respectively.
n = len(grid)
dp = [[-1 for _ in xrange(n)] for _ in xrange(n)]
dp[0][0] = grid[0][0]
max_len = 2 * (n-1)
directions = [(0, 0), (-1, 0), (0, -1), (-1, -1)]
for k in xrange(1, max_len+1):
for i in reversed(xrange(max(0, k-n+1), min(k+1, n))): # 0 <= i < n, 0 <= k-i < n
for j in reversed(xrange(i, min(k+1, n))): # i <= j < n, 0 <= k-j < n
if grid[i][k-i] == -1 or grid[j][k-j] == -1:
dp[i][j] = -1
continue
cnt = grid[i][k-i]
if i != j:
cnt += grid[j][k-j]
max_cnt = -1
for direction in directions:
ii, jj = i+direction[0], j+direction[1]
if ii >= 0 and jj >= 0 and dp[ii][jj] >= 0:
max_cnt = max(max_cnt, dp[ii][jj]+cnt)
dp[i][j] = max_cnt
return max(dp[n-1][n-1], 0)  

Python:

class Solution(object):
def cherryPickup(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if grid[-1][-1] == -1: return 0 # set up cache
self.grid = grid
self.memo = {}
self.N = len(grid) return max(self.dp(0, 0, 0, 0), 0) def dp(self, i1, j1, i2, j2):
# already stored: return
if (i1, j1, i2, j2) in self.memo: return self.memo[(i1, j1, i2, j2)] # end states: 1. out of grid 2. at the right bottom corner 3. hit a thorn
N = self.N
if i1 == N or j1 == N or i2 == N or j2 == N: return -1
if i1 == N-1 and j1 == N-1 and i2 == N-1 and j2 == N-1: return self.grid[-1][-1]
if self.grid[i1][j1] == -1 or self.grid[i2][j2] == -1: return -1 # now can take a step in two directions at each end, which amounts to 4 combinations in total
dd = self.dp(i1+1, j1, i2+1, j2)
dr = self.dp(i1+1, j1, i2, j2+1)
rd = self.dp(i1, j1+1, i2+1, j2)
rr = self.dp(i1, j1+1, i2, j2+1)
maxComb = max([dd, dr, rd, rr]) # find if there is a way to reach the end
if maxComb == -1:
out = -1
else:
# same cell, can only count this cell once
if i1 == i2 and j1 == j2:
out = maxComb + self.grid[i1][j1]
# different cell, can collect both
else:
out = maxComb + self.grid[i1][j1] + self.grid[i2][j2] # cache result
self.memo[(i1, j1, i2, j2)] = out
return out    

C++:

class Solution {
public:
int cherryPickup(vector<vector<int>>& grid) {
int n = grid.size(), mx = 2 * n - 1;
vector<vector<int>> dp(n, vector<int>(n, -1));
dp[0][0] = grid[0][0];
for (int k = 1; k < mx; ++k) {
for (int i = n - 1; i >= 0; --i) {
for (int p = n - 1; p >= 0; --p) {
int j = k - i, q = k - p;
if (j < 0 || j >= n || q < 0 || q >= n || grid[i][j] < 0 || grid[p][q] < 0) {
dp[i][p] = -1;
continue;
}
if (i > 0) dp[i][p] = max(dp[i][p], dp[i - 1][p]);
if (p > 0) dp[i][p] = max(dp[i][p], dp[i][p - 1]);
if (i > 0 && p > 0) dp[i][p] = max(dp[i][p], dp[i - 1][p - 1]);
if (dp[i][p] >= 0) dp[i][p] += grid[i][j] + (i != p ? grid[p][q] : 0);
}
}
}
return max(dp[n - 1][n - 1], 0);
}
};

  

All LeetCode Questions List 题目汇总

[LeetCode] 741. Cherry Pickup 捡樱桃的更多相关文章

  1. [LeetCode] Cherry Pickup 捡樱桃

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  2. LeetCode 741. Cherry Pickup

    原题链接在这里:https://leetcode.com/problems/cherry-pickup/ 题目: In a N x N grid representing a field of che ...

  3. 741. Cherry Pickup

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  4. [Swift]LeetCode741. 摘樱桃 | Cherry Pickup

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  5. Java实现 LeetCode 741 摘樱桃(DFS || 递推 || 传纸条)

    741. 摘樱桃 一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示: 0 表示这个格子是空的,所以你可以穿过它. 1 表示这个格子里装着一个樱桃,你可以摘到樱桃然 ...

  6. LeetCode741. Cherry Pickup

    https://leetcode.com/problems/cherry-pickup/description/ In a N x N grid representing a field of che ...

  7. 动态规划-Cherry Pickup

    2020-02-03 17:46:04 问题描述: 问题求解: 非常好的题目,和two thumb其实非常类似,但是还是有个一点区别,就是本题要求最后要到达(n - 1, n - 1),只有到达了(n ...

  8. leetcode动态规划题目总结

    Hello everyone, I am a Chinese noob programmer. I have practiced questions on leetcode.com for 2 yea ...

  9. LeetCode All in One题解汇总(持续更新中...)

    突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...

随机推荐

  1. Codeforces G. Bus Number(dfs排列)

    题目描述: Bus Number time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  2. Python 爬虫js加密破解(四) 360云盘登录password加密

    登录链接:https://yunpan.360.cn/mindex/login 这是一个md5 加密算法,直接使用 md5加密即可实现 本文讲解的是如何抠出js,运行代码 第一部:抓包 如图 第二步: ...

  3. 图森未来一道笔试题-迷宫难题【BFS找S->E的最短步数】

    时间限制:3秒 空间限制:262144K 图森未来的自动驾驶小卡车今天被派到了一个陌生的迷宫内部运输一些货物. 工程师小图已经提前拿到了这个迷宫的地图,地图是一个n*m的字符矩阵,上面包含四种不同的字 ...

  4. C#操作域用户ADHelper

    在C#中操作域用户,在项目中写的帮助类: using System; using System.Collections.Generic; using System.DirectoryServices; ...

  5. Python开发AI应用-国际象棋应用

    AI 部分总述     AI在做出决策前经过三个不同的步骤.首先,他找到所有规则允许的棋步(通常在开局时会有20-30种,随后会降低到几种).其次,它生成一个棋步树用来随后决定最佳决策.虽然树的大小随 ...

  6. Java学习 从0.1开始(一)

    写在前面: 之前从事过.NET,C,C++相关的开发,Java是一直没有学习的新领域.最近,应工作需要,开始学习Java相关的知识.又因为新公司并没有完整的系统架构,所以学习方向会侧重架构方向(Cod ...

  7. PHP程序员最容易犯的Mysql错误

    对于大多数web应用来说,数据库都是一个十分基础性的部分.如果你在使用PHP,那么你很可能也在使用MySQL—LAMP系列中举足轻重的一份子. 对于很多新手们来说,使用PHP可以在短短几个小时之内轻松 ...

  8. pandas 6 时间

    类 备注 创建方法 Timestamp 时刻数据 to_datetime,Timestamp DatetimeIndex Timestamp的索引 to_datetime,date_range,Dat ...

  9. python完成加密参数sign计算并输出指定格式的字符串

    加密规则: 1.固定加密字符串+字符串组合(key/value的形式,并通过aissc码排序), 2.通过sha1算法对排序后的字符串进行加密, 3.最终输出需要的参数sign 4.完成请求参数数据的 ...

  10. [Codeforces 1265E]Beautiful Mirrors

    Description 题库链接 一共有 \(n\) 个关卡,你初始在第一个关卡.通过第 \(i\) 个关卡的概率为 \(p_i\).每一轮你可以挑战一个关卡.若通过第 \(i\) 个关卡,则进入第 ...