🛫 网格图中鱼的最大数目
📝 题目描述
给你一个下标从0开始、大小为m x n
的二维整数数组grid
,其中下标在(r, c)
处的整数表示:
- 如果
grid[r][c] == 0
,那么它是一块陆地。 - 如果
grid[r][c] > 0
,那么它是一块水域,且包含grid[r][c]
条鱼。
一位渔夫可以从任意水域格子(r, c)
出发,然后执行以下操作任意次:
- 捕捞格子
(r, c)
处所有鱼,或者 - 移动到相邻的水域格子。
请你返回渔夫最优策略下,最多可以捕捞多少条鱼。如果没有水域格子,请你返回
格子(r, c)
相邻的格子为(r, c + 1)
、(r, c - 1)
、(r + 1, c)
和(r - 1, c)
,前提是相邻格子在网格图内。
📋 代码模板
class Solution {
public int findMaxFish(int[][] grid) {
}
}
function findMaxFish(grid: number[][]): number {
}
💡 提示
🚀 示例
示例一
输入grid
为[[0,2,1,0],[4,0,0,3],[1,0,0,4],[0,3,2,0]]
,输出为7
。渔夫总共有
示例二
输入grid
为[[1,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]]
,输出为1
。渔夫总共有
示例三
输入grid
为[[1,3,0,0,0,0],[7,5,2,0,0,5],[0,0,1,0,0,38],[0,0,4,7,8,0]]
,输出为43
。渔夫总共有
🖊️ 题解
该题本质上是在网格中找各个连通块的元素总和,并取最大值作为答案。
我们可以初始化一个值为 DFS
或BFS
。在搜索过程中,每遇到一个尚未访问过的水域单元格(值大于
为了进一步节省算法的空间,我们可以直接将网格中单元格的值更新为
DFS
class Solution {
private final static int[][] DIRS = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private final static int VISITED = -1;
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));
}
}
}
return maxFish;
}
private int dfs(int[][] grid, int i, int j) {
if (i < 0 || i > grid.length - 1 || j < 0 || j > grid[0].length - 1
|| grid[i][j] <= 0) {
return 0;
}
int fishes = grid[i][j];
grid[i][j] = VISITED;
for (int d = 0; d < 4; d++) {
fishes += dfs(grid, i + DIRS[d][0], j + DIRS[d][1]);
}
return fishes;
}
}
const DIRS: number[][] = [[-1, 0], [1, 0], [0, -1], [0, 1]];
const VISITED = -1;
function findMaxFish(grid: number[][]): number {
const m = grid.length, n = grid[0].length;
const dfs = (i: number, j: number): number => {
if (i < 0 || i > grid.length - 1 || j < 0 || j > grid[0].length - 1
|| grid[i][j] <= 0) {
return 0;
}
let fishes = grid[i][j];
grid[i][j] = VISITED;
for (let d = 0; d < 4; d++) {
fishes += dfs(i + DIRS[d][0], j + DIRS[d][1]);
}
return fishes;
}
let maxFish = 0;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] > 0) {
maxFish = Math.max(maxFish, dfs(i, j));
}
}
}
return maxFish;
}
BFS
class Solution {
private final static int[][] DIRS = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private final static int VISITED = -1;
public int findMaxFish(int[][] grid) {
int m = grid.length, n = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
int maxFish = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] > 0) {
int fishes = grid[i][j];
queue.offer(new int[]{i, j});
grid[i][j] = VISITED;
while (!queue.isEmpty()) {
int[] cell = queue.poll();
int oldI = cell[0], oldJ = cell[1];
for (int d = 0; d < 4; d++) {
int currentI = oldI + DIRS[d][0], currentJ = oldJ + DIRS[d][1];
if (currentI >= 0 && currentI < m && currentJ >= 0 && currentJ < n
&& grid[currentI][currentJ] > 0) {
fishes += grid[currentI][currentJ];
queue.offer(new int[]{currentI, currentJ});
grid[currentI][currentJ] = VISITED;
}
}
}
maxFish = Math.max(maxFish, fishes);
}
}
}
return maxFish;
}
}
const DIRS: number[][] = [[-1, 0], [1, 0], [0, -1], [0, 1]];
const VISITED = -1;
function findMaxFish(grid: number[][]): number {
const m = grid.length, n = grid[0].length;
const queue: number[][] = [];
let maxFish = 0;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] > 0) {
let fishes = grid[i][j];
queue.push([i, j]);
grid[i][j] = VISITED;
while (queue.length > 0) {
const cell: number[] = queue.shift()!;
const oldI = cell[0], oldJ = cell[1];
for (let d = 0; d < 4; d++) {
const currentI = oldI + DIRS[d][0], currentJ = oldJ + DIRS[d][1];
if (currentI >= 0 && currentI < m && currentJ >= 0 && currentJ < n
&& grid[currentI][currentJ] > 0) {
fishes += grid[currentI][currentJ];
queue.push([currentI, currentJ]);
grid[currentI][currentJ] = VISITED;
}
}
}
maxFish = Math.max(maxFish, fishes);
}
}
}
return maxFish;
}
💭 复杂度分析
基于DFS
的解决方案的复杂度分析如下。
- 时间复杂度:
。其中 与 分别为网格的行数和列数。 - 空间复杂度:
。在最坏情况下,整个网格均为陆地,深度优先搜索的深度达到 。
基于BFS
的解决方案的复杂度分析如下。
- 时间复杂度:
。其中 与 分别为网格的行数和列数。 - 空间复杂度:
。