Medium
题目描述
给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid ,其中下标 (r, c) 处的值表示:
- 如果
grid[r][c] = 0,那么它是一块 陆地 。 - 如果
grid[r][c] > 0,那么它是一块 水域 ,且包含grid[r][c]条鱼。
一位渔夫可以从任意 水域 格子 (r, c) 出发,然后执行下述操作任意次:
- 捕捞格子
(r, c)处所有的鱼,或者 - 移动到相邻的 水域 格子。
请你返回渔夫最优策略下, 最多 可以捕捞多少条鱼。如果没有水域格子,请返回 0 。
格子 (r, c) 相邻的格子为 (r, c + 1) 、(r, c - 1) 、(r + 1, c) 或者 (r - 1, c) ,前提是相邻格子在网格图内。
示例 1:
输入:grid = [[0,2,1,0],[4,0,0,3],[1,0,0,4],[0,3,2,0]]
输出:7
解释:渔夫可以从格子 (1,3) 出发,捕捞 3 条鱼,然后移动到格子 (2,3) ,捕捞 4 条鱼。
示例 2:
输入:grid = [[1,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]]
输出:1
解释:渔夫可以从格子 (0,0) 或者 (3,3) 出发,捕捞 1 条鱼。
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 100 <= grid[i][j] <= 10
解题思路
这道题的核心思想是找到连通的水域区域,并计算每个连通区域中鱼的总数,最后返回最大值。
解题思路:
- 连通性分析:由于渔夫只能在相邻的水域格子间移动,问题实际上是寻找所有连通的水域区域。
- 深度优先搜索(DFS):对于每个未访问过的水域格子,使用DFS遍历整个连通区域,累计该区域内所有鱼的数量。
- 状态标记:为避免重复计算,需要标记已访问过的格子。可以直接修改原数组,将访问过的格子设为0。
- 最优解:遍历所有可能的起始点,记录能捕获的最大鱼数。
算法步骤:
- 遍历网格中的每个格子
- 如果格子包含鱼(值大于0且未访问),从该格子开始DFS
- DFS过程中累计当前连通区域的鱼数,并标记访问过的格子
- 更新全局最大值
- 返回最终结果
这种方法能保证每个水域格子只被访问一次,效率较高。由于网格规模较小(最大10x10),时间复杂度完全可以接受。
代码实现
class Solution {
public:
int findMaxFish(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
int maxFish = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] > 0) {
maxFish = max(maxFish, dfs(grid, i, j, m, n));
}
}
}
return maxFish;
}
private:
int dfs(vector<vector<int>>& grid, int r, int c, int m, int n) {
if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] == 0) {
return 0;
}
int fish = grid[r][c];
grid[r][c] = 0; // 标记为已访问
// 向四个方向探索
fish += dfs(grid, r + 1, c, m, n);
fish += dfs(grid, r - 1, c, m, n);
fish += dfs(grid, r, c + 1, m, n);
fish += dfs(grid, r, c - 1, m, n);
return fish;
}
};
class Solution:
def findMaxFish(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
max_fish = 0
def dfs(r, c):
if r < 0 or r >= m or c < 0 or c >= n or grid[r][c] == 0:
return 0
fish = grid[r][c]
grid[r][c] = 0 # 标记为已访问
# 向四个方向探索
fish += dfs(r + 1, c)
fish += dfs(r - 1, c)
fish += dfs(r, c + 1)
fish += dfs(r, c - 1)
return fish
for i in range(m):
for j in range(n):
if grid[i][j] > 0:
max_fish = max(max_fish, dfs(i, j))
return max_fish
public class Solution {
public int FindMaxFish(int[][] grid) {
int m = grid.Length, n = grid[0].Length;
int maxFish = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] > 0) {
maxFish = Math.Max(maxFish, DFS(grid, i, j, m, n));
}
}
}
return maxFish;
}
private int DFS(int[][] grid, int r, int c, int m, int n) {
if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] == 0) {
return 0;
}
int fish = grid[r][c];
grid[r][c] = 0; // 标记为已访问
// 向四个方向探索
fish += DFS(grid, r + 1, c, m, n);
fish += DFS(grid, r - 1, c, m, n);
fish += DFS(grid, r, c + 1, m, n);
fish += DFS(grid, r, c - 1, m, n);
return fish;
}
}
var findMaxFish = function(grid) {
const m = grid.length, n = grid[0].length;
let maxFish = 0;
function dfs(r, c) {
if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c]
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(m × n),其中 m 和 n 分别为网格的行数和列数。每个格子最多被访问一次 |
| 空间复杂度 | O(m × n),主要来自递归调用栈的深度,最坏情况下整个网格都是连通的水域 |
相关题目
. Number of Islands (Medium)
. Max Area of Island (Medium)