3148. 矩阵中的最大得分

题目描述:

给你一个由 正整数 组成、大小为 m x n 的矩阵 grid。你可以从矩阵中的任一单元格移动到另一个位于正下方或正右侧的任意单元格(不必相邻)。从值为 c1 的单元格移动到值为 c2 的单元格的得分为 c2 - c1

你可以从 任一 单元格开始,并且必须至少移动一次。

返回你能得到的 最大 总得分。

示例 1:

grid1
输入: grid = [[9,5,7,3],[8,9,6,1],[6,7,14,3],[2,5,3,1]]
输出: 9
解释: 从单元格 `(0, 1)` 开始,并执行以下移动:
- 从单元格 `(0, 1)` 移动到 `(2, 1)`,得分为 `7 - 5 = 2` 。
- 从单元格 `(2, 1)` 移动到 `(2, 2)`,得分为 `14 - 7 = 7` 。
总得分为 `2 + 7 = 9` 。

示例 2:

moregridsdrawio-1
输入: grid = [[4,3,2],[3,2,1]]
输出:-1
解释: 从单元格 `(0, 0)` 开始,执行一次移动:从 `(0, 0)` 到 `(0, 1)` 。得分为 `3 - 4 = -1` 。

提示:

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 1000
  • 4 <= m * n <= 105
  • 1 <= grid[i][j] <= 105

解题分析及思路:

方法:动态规划

思路:

本题实际是 你需要矩阵中某个单元格移动到该单元格右侧或者下方的任意单元格,可以选择

  • 只移动到右侧单元格
  • 只移动到下方单元格
  • 移动到右侧单元格后再次移动到下方单元格(等同于 移动到下方单元格后再次移动到右侧单元格)

那么,最终移动到单元格(i,j)的元素可以来自(0 ~ i, 0 ~ j)(不包括(i,j)),该区域为单元格(i,j)的左上角。

最终,问题转换为找出位置(i,j)左上角的最小值,即dp[i][j],最终每个单元格的值 - dp[i][j],即为得分,取每个结果的最大值为最大得分。

dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), grid[i][j])

因为需要至少移动一步,所以初始化结果为grid[0][1] - grid[0][0](即默认从(0,0)移动到(0,1)),后续有更大结果将会更新。

func maxScore(grid [][]int) int {
	m := len(grid)
	n := len(grid[0])
	dp := make([][]int, m)

	for i := range dp {
		dp[i] = make([]int, n)
		for j := range dp[i] {
			dp[i][j] = math.MaxInt32
		}
	}

	ans := grid[0][1] - grid[0][0]
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			var temp = grid[i][j]
			if i > 0 {
				temp = min(temp, dp[i-1][j])
				ans = max(ans, grid[i][j]-dp[i-1][j])
			}
			if j > 0 {
				temp = min(temp, dp[i][j-1])
				ans = max(ans, grid[i][j]-dp[i][j-1])
			}
			dp[i][j] = temp
		}
	}
	return ans
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

复杂度:

  • 时间复杂度:O(n * m)
  • 空间复杂度:O(n * m)

执行结果:

  • 执行耗时:115 ms,击败了60.51% 的Go用户
  • 内存消耗:8.4 MB,击败了30.77% 的Go用户

通过次数 19.4K 提交次数 31.3K 通过率 62.1%

Related Posts

1026. 节点与其祖先之间的最大差值

## 题目描述:给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)示例 1: ![](/img/leetcode/1026节点与其祖先之间的最大差值/tmp-tre

read more

1038. 从二叉搜索树到更大和树

## 题目描述:给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。提醒一下, 二叉搜索树 满足下列约束条件:- 节点的左子树仅包含键 小于 节点键的节点。 - 节点的右子树仅包含键 大于 节点键的节点。 - 左右子树也必须是二叉搜索树。*示例 1:***![](/img/leetcode/

read more

105. 从前序与中序遍历序列构造二叉树

## 题目描述:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例 1: ``` 输入: preorder = [3,9,20,15,7], inorder = [

read more

106. 从中序与后序遍历序列构造二叉树

## 题目描述:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。示例 1: ``` 输入:inorder = [9,3,15,20,7], postorder

read more

109. 有序链表转换二叉搜索树

## 题目描述:给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。示例 1: ``` 输入: head = [-10,-3,0,5,9] 输出: [0,-3,9

read more

114. 二叉树展开为链表

## 题目描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:- 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。示例 1: ``` 输入:root

read more