You are given an n x n binary matrix grid. You are allowed to change at most one 0 to be 1.
Return the size of the largest island in grid after applying this operation.
An island is a 4-directionally connected group of 1s.
Example 1:
Input: grid = [[1,0],[0,1]]
Output: 3
Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
Example 2:
Input: grid = [[1,1],[1,0]]
Output: 4
Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4.
Example 3:
Input: grid = [[1,1],[1,1]]
Output: 4
Explanation: Can’t change any 0 to 1, only one island with area = 4.
Constraints:
n == grid.length
n == grid[i].length
1 <= n <= 500
grid[i][j] is either 0 or 1.
第一层:
- 我们需要将相连的1组成一个个独立的岛
- 挨个检查grid中的0,上下左右不同岛的面积相加,然后取最大值
第二层:
- 相连1组合成岛的问题, 给每个1一个独立的编号,然后重复遍历grid, 将每个元素与其上下左右的邻居进行对比,如果邻居们的最大编号比它的编号大,那就把它的编号改成这个最大编号。同时我们用一个数组记录每个编号对应的元素数量(面积), 修改元素编号的时候同时要对这个数组进行修改, 这样最后我们确定岛面积的时候直接查阅这个数组就可以了,不用再进行重新遍历。最终我们会得到一个个独立的拥有一致编号的岛。
- 首先我们可以确定的是,最终的答案至少是这些岛中的面积最大值,最极端的情况就是,整个grid中都是1,这样我们就得到了一个面积是n²的岛。其次的情况就是有若干个岛,但是相互之间相隔的不止一个0,这样我们得到的答案就是最大岛的面积+1。最后的情况就是有若干个岛之间只有一个0作为间隔,这样的话,答案就是这些岛的面积加和加1的最大值。但是实际编码的时候不需要做这种判断,我们检查grid中的每个0元素,把它上下左右的邻居编号拿到,然后注意,我们只把不同编号的岛的面积加起来就好了。不是全部相加,比如说一个0,它的左边和上边都跟100号岛接壤,右边和下边都跟200号岛接壤, 这时的面积应该是area[100] + area[200] + 1而不是area[100]+area[100]+area[200]+area[200]+1。还有一种情况就是这个0周边也是0,这也不用单独处理,因为我们的area[0] == 0, 也就是说我们也把0看做是岛,只不过岛的编号是0且面积也是0。
use std::collections::HashSet;
use std::iter::FromIterator;
impl Solution {
pub fn largest_island(mut grid: Vec<Vec<i32>>) -> i32 {
let mut counts = vec![0; 250000];
let mut val = 1;
grid.iter_mut().for_each(|l| {
l.iter_mut().for_each(|v| {
if v == &mut 1 {
*v = val;
counts[val as usize] = 1;
val += 1;
}
});
});
loop {
let mut changed = false;
for i in 0..grid.len() {
for j in 0..grid[0].len() {
if grid[i][j] > 0 {
let left = if j > 0 { grid[i][j - 1] } else { 0 };
let right = if j < grid[0].len() - 1 { grid[i][j + 1] } else { 0 };
let top = if i > 0 { grid[i - 1][j] } else { 0 };
let bottom = if i < grid.len() - 1 { grid[i + 1][j] } else { 0 };
let max = left.max(right).max(top).max(bottom);
if max > grid[i][j] {
counts[grid[i][j] as usize] -= 1;
counts[max as usize] += 1;
grid[i][j] = max;
changed = true;
}
}
}
}
if !changed {
break;
}
}
let mut ans = *counts.iter().max().unwrap();
for i in 0..grid.len() {
for j in 0..grid[0].len() {
if grid[i][j] == 0 {
let left = if j > 0 { grid[i][j - 1] } else { 0 };
let right = if j < grid[0].len() - 1 { grid[i][j + 1] } else { 0 };
let top = if i > 0 { grid[i - 1][j] } else { 0 };
let bottom = if i < grid.len() - 1 { grid[i + 1][j] } else { 0 };
let vals: HashSet<i32> = HashSet::from_iter(vec![left, right, top, bottom].into_iter());
let count = vals.into_iter().map(|k| counts[k as usize]).sum::<i32>() + 1;
ans = ans.max(count);
}
}
}
ans
}
}
后记:
个人感觉,把自己的思路写明白远远比解题难得多,很多东西自己脑子里面想起来很简单,但是要想准确表达出来还是要费些功夫,以前我一直仅想把这个微博作为自己的自留地,记录意义要远大于分享。写下的东西不需要太详细自己能看懂就可以了,更多的是想留下自己的足迹。但是前几天看了一篇文章,说程序员的沟通和表达的能力其实与专业知识一样重要,毕竟在这个开源的时代已经没有几个人能凭一己之力创造奇迹了。所以我想或许这里可以变成一个锻炼自己的平台。