In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in the given list mines which are 0. What is the largest axis-aligned plus sign of 1s contained in the grid? Return the order of the plus sign. If there is none, return 0.

An "axis-aligned plus sign of 1s of order k" has some center grid[x][y] = 1 along with 4 arms of length k-1going up, down, left, and right, and made of 1s. This is demonstrated in the diagrams below. Note that there could be 0s or 1s beyond the arms of the plus sign, only the relevant area of the plus sign is checked for 1s.

Examples of Axis-Aligned Plus Signs of Order k:

Order 1:
000
010
000 Order 2:
00000
00100
01110
00100
00000 Order 3:
0000000
0001000
0001000
0111110
0001000
0001000
0000000

Example 1:

Input: N = 5, mines = [[4, 2]]
Output: 2
Explanation:
11111
11111
11111
11111
11011
In the above grid, the largest plus sign can only be order 2. One of them is marked in bold.

Example 2:

Input: N = 2, mines = []
Output: 1
Explanation:
There is no plus sign of order 2, but there is of order 1.

Example 3:

Input: N = 1, mines = [[0, 0]]
Output: 0
Explanation:
There is no plus sign, so return 0.

Note:

  1. N will be an integer in the range [1, 500].
  2. mines will have length at most 5000.
  3. mines[i] will be length 2 and consist of integers in the range [0, N-1].
  4. (Additionally, programs submitted in C, C++, or C# will be judged with a slightly smaller time limit.)

这道题给了我们一个数字N,表示一个NxN的二位数字,初始化均为1,又给了一个mines数组,里面是一些坐标,表示数组中这些位置都为0,然后让我们找最大的加型符号。所谓的加型符号是有数字1组成的一个十字型的加号,题目中也给出了长度分别为1,2,3的加型符号的样子。好,理解了题意以后,我们来想想该如何破题。首先,最简单的就是考虑暴力搜索啦,以每个1为中心,向四个方向分别去找,只要任何一个方向遇到了0就停止,然后更新结果res。令博主感到惊讶的是,此题的OJ居然允许Brute Force的解法通过,还是比较大度的,参见代码如下:

解法一:

class Solution {
public:
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
int res = ;
vector<vector<int>> mat(N, vector<int>(N, ));
for (auto mine : mines) mat[mine[]][mine[]] = ;
for (int i = ; i < N; ++i) {
for (int j = ; j < N; ++j) {
int k = ;
while (canExpand(mat, N, i, j, k)) ++k;
res = max(res, k);
}
}
return res;
}
bool canExpand(vector<vector<int>>& mat, int N, int x, int y, int k) {
if (x - k < || y - k < || x + k >= N || y + k >= N) return false;
return mat[x - k][y] && mat[x][y + k] && mat[x + k][y] && mat[x][y - k];
}
};

如果我们只想出暴力搜索的解法,就不再管这道题了的话,那在面试的时候就比较悬了。毕竟立方级的时间复杂度实在是太高了,我们必须要进行优化。暴力搜索的时间复杂度之所以高的原因是因为对于每一个1都要遍历其上下左右四个方向,有大量的重复计算,我们为了提高效率,可以对于每一个点,都计算好其上下左右连续1的个数。博主最先用的方法是建立四个方向的dp数组,dp[i][j]表示 (i, j) 位置上该特定方向连续1的个数,那么就需要4个二维dp数组,举个栗子,比如:

原数组:


那么我们建立left数组是当前及其左边连续1的个数,如下所示:


right数组是当前及其右边连续1的个数,如下所示:


up数组是当前及其上边连续1的个数,如下所示:


down数组是当前及其下边连续1的个数,如下所示:


我们需要做的是在这四个dp数组中的相同位置的四个值中取最小的一个,然后在所有的这些去除的最小值中选最大一个返回即可。为了节省空间,我们不用四个二维dp数组,而只用一个就可以了,因为对于每一个特定位置,我们只需要保留较小值,所以在更新的时候,只需要跟原来值相比取较小值即可。在计算down数组的时候,我们就可以直接更新结果res了,因为四个值都已经计算过了,我们就不用再重新在外面开for循环了,参见代码如下:

解法二:

class Solution {
public:
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
int res = , cnt = ;
vector<vector<int>> dp(N, vector<int>(N, ));
unordered_set<int> s;
for (auto mine : mines) s.insert(mine[] * N + mine[]);
for (int j = ; j < N; ++j) {
cnt = ;
for (int i = ; i < N; ++i) { // up
cnt = s.count(i * N + j) ? : cnt + ;
dp[i][j] = cnt;
}
cnt = ;
for (int i = N - ; i >= ; --i) { // down
cnt = s.count(i * N + j) ? : cnt + ;
dp[i][j] = min(dp[i][j], cnt);
}
}
for (int i = ; i < N; ++i) {
cnt = ;
for (int j = ; j < N; ++j) { // left
cnt = s.count(i * N + j) ? : cnt + ;
dp[i][j] = min(dp[i][j], cnt);
}
cnt = ;
for (int j = N - ; j >= ; --j) { // right
cnt = s.count(i * N + j) ? : cnt + ;
dp[i][j] = min(dp[i][j], cnt);
res = max(res, dp[i][j]);
}
}
return res;
}
};

我们可以进一步的压缩代码,使其更加简洁,我们发现其实只要分别用四个变量l,r,u,d来表示四个方向连续1的个数,既可以将for循环糅合在一起。注意里面内嵌的for循环其实是两个for循环,由j和k分别控制,那么只要弄清i,j,k坐标的位置,就可以同时更新四个方向的dp值了,最后dp数组更新好了之后,我们再秀一波,只用一个for循环来遍历二维数组,其实就是把二维坐标压缩成了一个数字,再解压缩,参见代码如下:

解法三:

class Solution {
public:
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
int res = ;
vector<vector<int>> dp(N, vector<int>(N, N));
for (auto mine : mines) dp[mine[]][mine[]] = ;
for (int i = ; i < N; ++i) {
int l = , r = , u = , d = ;
for (int j = , k = N - ; j < N; ++j, --k) {
dp[i][j] = min(dp[i][j], l = (dp[i][j] ? l + : ));
dp[j][i] = min(dp[j][i], u = (dp[j][i] ? u + : ));
dp[i][k] = min(dp[i][k], r = (dp[i][k] ? r + : ));
dp[k][i] = min(dp[k][i], d = (dp[k][i] ? d + : ));
}
}
for (int k = ; k < N * N; ++k) res = max(res, dp[k / N][k % N]);
return res;
}
};

类似题目:

Cheapest Flights Within K Stops

Minimum Swaps To Make Sequences Increasing

Soup Servings

参考资料:

https://leetcode.com/problems/largest-plus-sign/solution/

https://leetcode.com/problems/largest-plus-sign/discuss/113314/JavaC++Python-O(N2)-solution-using-only-one-grid-matrix

https://leetcode.com/problems/largest-plus-sign/discuss/113350/C++-simple-brute-force-easy-to-understand-with-detailed-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Largest Plus Sign 最大的加型符号的更多相关文章

  1. 【LeetCode】764. Largest Plus Sign 解题报告(Python)

    [LeetCode]764. Largest Plus Sign 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn ...

  2. 【leetcode】Largest Plus Sign

    题目如下: In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in the giv ...

  3. [Swift]LeetCode764. 最大加号标志 | Largest Plus Sign

    In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except those cells in the given lis ...

  4. leetcode Largest Rectangle in Histogram 单调栈

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4052343.html 题目链接 leetcode Largest Rectangle in ...

  5. 764. Largest Plus Sign最大的dfs十字架

    [抄题]: 求挖掉一些区域后,能允许出现的最大十字架 In a 2D grid from (0, 0) to (N-1, N-1), every cell contains a 1, except t ...

  6. [LeetCode] Largest Rectangle in Histogram O(n) 解法详析, Maximal Rectangle

    Largest Rectangle in Histogram Given n non-negative integers representing the histogram's bar height ...

  7. 解决VS2012【加载......符号缓慢】的问题

    http://blog.csdn.net/shi0090/article/details/19411777 最近在用VS2012调试时,经常出现"加载......符号缓慢的问题", ...

  8. 解决Visual Studio 加载符号卡死情况

    VS 加载符号 过慢或卡死的情况都可以用这种方法 打开VS的[工具]-[选项]-[调试]-[符号], 如下图所示: 1. 先取消勾选 ”Microsoft符号服务器” 2. 再点击 “清空符号缓存” ...

  9. 在c++运行后出现PDB或者什么巴拉巴拉已经加载符号了的话

    “stl常用排序算法.exe”(Win32): 已加载“E:\vs2015\project\stl常用排序算法\Debug\stl常用排序算法.exe”.已加载符号. “stl常用排序算法.exe”( ...

随机推荐

  1. Konckout第五个实例:各种事件绑定

    点击加一: <!doctype html> <html > <head> <meta http-equiv="Content-Type" ...

  2. KVM之二:配置网络

    1.安装KVM a.通过yum安装虚拟化的软件包 [root@kvm ~ ::]#yum install -y kvm virt-* libvirt bridge-utils qemu-img 说明: ...

  3. React Native 轻松集成分享功能(Android 篇)

    关于推送的集成请参考这篇文章,关于统计的集成请参考这篇文章,本篇文章将引导你集成分享功能. 在集成插件之前,需要在各大开放平台上成功注册应用,并通过审核(支持 3 个可选的主流平台).支持的平台如下: ...

  4. C语言第二周作业----分支结构

    一.PTA实验作业 题目1.7-1计算分段函数 本题目要求计算下列分段函数f(x)的值: 注:可在头文件中包含math.h,并调用sqrt函数求平方根,调用pow函数求幂. 1.实验代码 int ma ...

  5. c字符数组

    一.PTA实验作业 题目1:统计一行文本的单词个数 1. 本题PTA提交列表 2. 设计思路 定义一个长度为1000的字符数组str[1000] 在定义 i=0,cnt=0:cnt用来记录单词的个数 ...

  6. 大数据技术Hadoop笔试题

    Hadoop有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上.以下是由应届毕业生网小编J.L为您整理推荐的面试笔试题目和经验,欢迎参考阅读. 单项选择题 1. 下面哪个程序负责 H ...

  7. Flask 扩展 HTTP认证

    Restful API不保存状态,无法依赖Cookie及Session来保存用户信息,自然也无法使用Flask-Login扩展来实现用户认证.所以这里,我们就要介绍另一个扩展,Flask-HTTPAu ...

  8. 【iOS】swift-获取webView的高度

        func webViewDidFinishLoad(webView: UIWebView) {         let webHeightStr = webView.stringByEvalu ...

  9. java语法基础(总结)

    1,关键字:其实就是某种语言赋予了特殊含义的单词. 保留字:其实就是还没有赋予特殊含义,但是准备日后要使用过的单词. 2,标示符:其实就是在程序中自定义的名词.比如类名,变量名,函数名.包含 0-9. ...

  10. 剑指offer-数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...