[leetcode]Largest Plus Sign
链接:https://leetcode.com/problems/largest-plus-sign/description/
Question
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 1
s 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-1
going up, down, left, and right, and made of 1
s. This is demonstrated in the diagrams below. Note that there could be 0
s or 1
s beyond the arms of the plus sign, only the relevant area of the plus sign is checked for 1s.
Example
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
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:
N will be an integer in the range [1, 500].
mines will have length at most 5000.
mines[i] will be length 2 and consist of integers in the range [0, N-1].
(Additionally, programs submitted in C, C++, or C# will be judged with a slightly smaller time limit.)
Solution 1[TLE]
// 虽然用到了动归,但是时间复杂度太大,还是超时
class Solution {
public:
#define Pair pair<int, int>
int direction[4][2] = {
{1,0},
{-1,0},
{0,1},
{0,-1}
};
bool inMap(int x, int y, int N) { return x >= 0 && x < N && y >= 0 && y < N; }
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
int K = (N+1)/2;
vector<vector<int> > mp;
mp.resize(N);
for (int i = 0; i < N; i++) mp[i].resize(N, 1);
for (int i = 0; i < mines.size(); i++)
if (mines[i].size() > 0)
mp[mines[i][0]][mines[i][1]] = 0;
int max_order = 0;
set<Pair> myset;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
// dp[i][j] = mp[i][j];
if (mp[i][j]) myset.insert(Pair(i, j));
max_order = max(max_order, mp[i][j]);
}
}
for (int p = 2; p <= K; p++) {
bool K_success = false;
for (auto it = myset.begin(); it != myset.end(); ) {
int i = it->first;
int j = it->second;
bool suceess = true;
for (int k = 0; k < 4; k++) {
int x = i+direction[k][0]*(p-1);
int y = j+direction[k][1]*(p-1);
if (!inMap(x, y, N) || mp[x][y] == 0) {
// 这里记得更新,因为没有保存次数p
// dp[i][j] = false;
it = myset.erase(it);
suceess = false;
break;
}
}
if (suceess) {
max_order = p;
K_success = true;
it++;
}
}
if (!K_success) break;
}
return max_order;
}
};
思路:采用动归的方法,就是遍历K次,看每一个点是否满足order k。
Solution 2[Accepted]
class Solution {
public:
#define inf 0x3fffffff
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
vector<vector<int> > mp;
mp.resize(N);
for (int i = 0; i < N; i++) mp[i].resize(N, 1);
for (int i = 0; i < mines.size(); i++)
if (mines[i].size() > 0)
mp[mines[i][0]][mines[i][1]] = 0;
vector<vector<int> > dp;
dp.resize(N);
for (int i = 0; i < N; i++) dp[i].resize(N, inf);
vector<vector<int> > copy;
copy.resize(N);
for (int i = 0; i < N; i++) copy[i].resize(N, inf);
// 左
for (int i = 0; i < N; i++) dp[i][0] = mp[i][0];
for (int i = 0; i < N; i++) {
for (int j = 1; j < N; j++) {
if (mp[i][j] == 0) {
dp[i][j] = 0;
} else {
dp[i][j] = min(dp[i][j], dp[i][j-1]+1);
}
}
}
// 右
for (int i = 0; i < N; i++) copy[i][N-1] = mp[i][N-1];
for (int i = 0; i < N; i++) {
for (int j = N-2; j >= 0; j--) {
if (mp[i][j] == 0) {
copy[i][j] = 0;
} else {
copy[i][j] = min(copy[i][j], copy[i][j+1]+1);
}
}
}
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
dp[i][j] = min(dp[i][j], copy[i][j]);
copy.clear();
copy.resize(N);
for (int i = 0; i < N; i++) copy[i].resize(N, inf);
// 上
for (int j = 0; j < N; j++) copy[0][j] = mp[0][j];
for (int j = 0; j < N; j++) {
for (int i = 1; i < N; i++) {
if (mp[i][j] == 0) {
copy[i][j] = 0;
} else {
copy[i][j] = min(copy[i][j], copy[i-1][j]+1);
}
}
}
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
dp[i][j] = min(dp[i][j], copy[i][j]);
copy.clear();
copy.resize(N);
for (int i = 0; i < N; i++) copy[i].resize(N, inf);
// 下
for (int j = 0; j < N; j++) copy[N-1][j] = mp[N-1][j];
for (int j = 0; j < N; j++) {
for (int i = N-2; i >= 0; i--) {
if (mp[i][j] == 0) {
copy[i][j] = 0;
} else {
copy[i][j] = min(copy[i][j], copy[i+1][j]+1);
}
}
}
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
dp[i][j] = min(dp[i][j], copy[i][j]);
int max_value = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
max_value = max(max_value, dp[i][j]);
}
}
return max_value;
}
};
思路:仍然采用动归的方法,总的想法是每个方向都遍历累加(比如011101的结果是012301)。但是必须注意的是,每次需要额外用一个矩阵进行存储,最后计算每个位置上的最小值。