[Leetcode]827.使用回溯+标记解决最大人工岛问题
在二维地图上, 0
代表海洋, 1
代表陆地,我们最多只能将一格 0
海洋变成 1
变成陆地。
进行填海之后,地图上最大的岛屿面积是多少?(上、下、左、右四个方向相连的 1
可形成岛屿)
示例 1:
输入: [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。
示例 2:
输入: [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。
示例 3:
输入: [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。
说明:
1 <= grid.length = grid[0].length <= 50
0 <= grid[i][j] <= 1
思路:
通过题目我们寻找一种遍历的方法,对每个数字0,判断如果将其填海,面积为多少,记为area
。
用中文叙述就是:
area初始化为0
如果此海上面为陆地,area+上面连成片的陆地面积。
如果此海右面为陆地,area+右面连成片的陆地面积。
如果此海下面为陆地,area+下面连成片的陆地面积。
如果此海左面为陆地,area+左面连成片的陆地面积。
代码表示则是:
if(g[i-1][j]==1)area+=上面连成片的陆地面积;
if(g[i][j+1]==1)area+=右面连成片的陆地面积;
if(g[i+1][j]==1)area+=下面连成片的陆地面积;
if(g[i][j-1]==1)area+=左面连成片的陆地面积;
本题的目的就是找到这个最大的area
。
可是遍历的时候会有两个麻烦点
- 如果上下左右为连成一片的陆地呢,那按照上面的公式则会重复计算面积
- 边界判断
其实2好解决,每次查询的时候进行边界检查即可。
但是1的解决方式就很复杂,我的解决方式是通过增加两个记录数组,给连成片的陆地进行编号,计算上下左右的陆地面积,若遇到有相同的陆地编号则不进行计算。
unsigned tag[50][50]={0};
/*用来记录第X,Y块属于哪块陆地片,如果是0则表示这块属于海洋,初始化全部为0*/
int area[700]={0};
/***
每个块号面积为多少,记作area[tag_number]=the_area_of_this tag
也可以用容器unordered_map<int,unsigned>area节省空间
***/
举个例子,比如有一海洋为(X,Y),其中上面为陆地编号为1,右面为陆地(编号为1),下面的陆地编号也为1(说明这块土地与(X,Y)上面那块土地相连),左面为海(编号为0)
如下图画的,则area只用加一个标记为1的陆地面积其中一个就行了。
避开重复的数字有很多种方法,如unordered_map
,或者建一个大小为4的数组,进行位运算这些都是一种方法,就不一一介绍了。
Solution
/*对代码解释在代码的后面*/
class Solution
{
public:
unsigned tag[50][50] = {0};
int area[700] = {0};
unsigned landNum = 0, X, Y;
void search(const vector<vector<int>> &grid, const unsigned x, const unsigned y)
{
if (grid[x][y] == 1 && tag[x][y] == 0)
{
area[landNum]++;
tag[x][y] = landNum;
/*四个if是边界检查*/
if (x >= 1)
search(grid, x - 1, y);
if (x < X - 1)
search(grid, x + 1, y);
if (y >= 1)
search(grid, x, y - 1);
if (y < Y - 1)
search(grid, x, y + 1);
}
}
int largestIsland(vector<vector<int>> &grid)
{
unsigned maxAnswer = 0, ans;
X = grid.size();
Y = grid[0].size();
for (unsigned i = 0; i < X; i++)
{
for (unsigned j = 0; j < Y; j++)
{
if (grid[i][j] == 1 && tag[i][j] == 0)
{
landNum++;
search(grid, i, j);
}
}
}
/*define the direction*/
enum
{
UP = 0,
RIGHT,
DOWN,
LEFT
};
unsigned tagIsland[4];
unordered_map<unsigned,unsigned> count;
for (unsigned i = 0; i < X; i++)
{
for (unsigned j = 0; j < Y; j++)
{
if (grid[i][j] == 0)
{
ans = 1;
tagIsland[UP] = i >= 1 ? tag[i - 1][j] : 0;
tagIsland[RIGHT] = j < Y - 1 ? tag[i][j + 1] : 0;
tagIsland[DOWN] = i < X - 1 ? tag[i + 1][j] : 0;
tagIsland[LEFT] = j >= 1 ? tag[i][j - 1] : 0;
for (unsigned k = UP; k <= LEFT;k++){
if(count[tagIsland[k]]==0&&tagIsland[k]!=0){
ans += area[tagIsland[k]];
count[tagIsland[k]]=1;
}
}
maxAnswer = max(ans, maxAnswer);
count.clear();
}
}
}
if(maxAnswer==0)
return X * Y;
return maxAnswer;
}
};
我们首先通过search()函数对整个表进行回溯初始化,使所有单独的陆地都被编号。
然后通过对每块海洋填海后的总area进行判断,保留最大面积
maxAnswer
,即每次计算出新的area后都有maxAnswer=area>maxAnswer?area:maxAnswer;
在最后return前,如果
maxAnswer=0
则表示全部都是陆地,可以用反证法验证: 如果至少有一个海洋,maxAnswer
至少为1。全是陆地的话只用return整片陆地的总面积即可,即X*Y。
至此,这道题的其中一种做法就完成了。
[Leetcode]827.使用回溯+标记解决最大人工岛问题的更多相关文章
- Python基于回溯法解决01背包问题实例
Python基于回溯法解决01背包问题实例 这篇文章主要介绍了Python基于回溯法解决01背包问题,结合实例形式分析了Python回溯法采用深度优先策略搜索解决01背包问题的相关操作技巧,需要的朋友 ...
- Java实现 LeetCode 827 最大人工岛(DFS+暴力模拟)
827. 最大人工岛 在二维地图上, 0代表海洋, 1代表陆地,我们最多只能将一格 0 海洋变成 1变成陆地. 进行填海之后,地图上最大的岛屿面积是多少?(上.下.左.右四个方向相连的 1 可形成岛屿 ...
- 回溯法解决N皇后问题(以四皇后为例)
以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...
- 用试探回溯法解决N皇后问题
学校数据结构的课程实验之一. 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析: 设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能: 由n*n个方块 ...
- LeetCode Merge k Sorted Lists 解决报告
https://oj.leetcode.com/problems/merge-k-sorted-lists/ 归并K已经整理阵列,和分析算法的复杂. 解决报告:无论是不考虑优化,最简单的实现是要重新走 ...
- LeetCode编程训练 - 回溯(Backtracking)
回溯基础 先看一个使用回溯方法求集合子集的例子(78. Subsets),以下代码基本说明了回溯使用的基本框架: //78. Subsets class Solution { private: voi ...
- [LeetCode] 827. Making A Large Island
In a 2D grid of 0s and 1s, we change at most one 0 to a 1. After, what is the size of the largest is ...
- 回溯算法——解决n皇后问题
所谓回溯(backtracking)是通过系统地搜索求解问题的方法.这种方法适用于类似于八皇后这样的问题:求得问题的一个解比较困难,但是检查一个棋局是否构成解很容易. 不多说,放上n皇后的回溯问题代码 ...
- [LeetCode] 827. Making A Large Island 建造一个巨大岛屿
In a 2D grid of 0s and 1s, we change at most one 0 to a 1. After, what is the size of the largest is ...
随机推荐
- extern和include的作用
首先要搞清楚的是.h头文件中都是一些声明性的语句,是不分配内存的,所以头文件中有对函数的声明,有define语句,有没有实例化的结构体定义,但是没有对变量的定义(比如 int a),有的只是对外变量的 ...
- [leetcode]54. Spiral Matrix螺旋矩阵
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...
- Shell 数值、字符串比较
Shell脚本中,数值与字符串比较是不同的,因此要注意(注意[]括号内参数和括号之间有一个空格). 一.数值比较 -eq 等于,如: if [ $a -eq $b ] -ne 不等于,如: if ...
- 事件委托在ios下面失效
$(document).on("click","目标class",function(){ //安卓下点击可以,ios下面失效 }) 百度了下说是H5新定义的, ...
- 《JAVA程序设计》第四周总结
第四周作业总结 学习内容: 1.根据教材视频学习第五章:子类和继承 2.调试代码和解决问题 3.上周错题 4.代码托管 知识总结 子类:在类的声明中,通过使用关键字extends来定义一个类的子类. ...
- 嵌入Python | 调用Python模块中无参数的函数
开发环境 Python版本:3.6.4 (32-bit) 编辑器:Visual Studio Code C++环境:Visual Studio 2013 需求说明 在用VS2013编写的Win32程序 ...
- 对hadoop namenode -format执行过程的探究
引言 本文出于一个疑问:hadoop namenode -format到底在我的linux系统里面做了些什么? 步骤 第1个文件bin/hadoop Hadoop脚本位于hadoop根目录下的bi ...
- linux就该这么学,第五课,
今天讲的比较难理解,要重预习和复习 今天讲了2个多小进,主要讲了SHELL,shell的组成:第一行为脚本声明 #!/bin/bash ,第二行为脚本的注释信息,第三为 脚本的执行语句 接收用户参 ...
- LB+ECS+RDS经典架构图例及注意事项
LB+ECS+RDS经典架构图例及注意事项
- ABP框架系列之五十四:(XSRF-CSRF-Protection-跨站请求伪造保护)
Introduction "Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a maliciou ...