第一题直接模拟,第二题可以手动打表。
5285. 元素和小于等于阈值的正方形的最大边长
显然,这是一个矩阵前缀和+二分。如果不用二分也能果,时间复杂度为,使用二分后时间复杂度为,我们使用加二分的方法去做。(一般的极限在左右)。
矩阵前缀和模板;二分查找最后一个小于等于和第一个大于等于某对象的数组元素位置模板。
class Solution {
public:
int bian(vector<vector<int>>& mat, int x)
{
int m = mat.size(), n = mat[0].size();
int res = 0x3f3f3f3f;
for(int i = 1; i <= m-x; i++)
for(int j = 1; j <= n-x; j++)
{
int temp = mat[i+x-1][j+x-1]-mat[i-1][j+x-1]-mat[i+x-1][j-1]+mat[i-1][j-1];
res = min(res, temp);
}
return res;
}
int maxSideLength(vector<vector<int>>& mat, int threshold) {
int m = mat.size(), n = mat[0].size();
// 用于提前判断不存在这样的子方阵
bool flag = false;
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
if(mat[i][j]<=threshold) flag = true;
if(!flag) return 0;
// p为矩阵前缀和
vector<vector<int>> p(m+1, vector<int>(n+1, 0));
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
p[i][j] += p[i-1][j]+p[i][j-1]-p[i-1][j-1]+mat[i-1][j-1];
// 二分得到答案
int l = 0, r = min(m, n), mid = 1;
while(l<=r)
{
mid = l+r>>1;
if(bian(p, mid)>threshold) r = mid-1;
else l = mid+1;
}
return l-1;
}
};
5286. 网格中的最短路径
这是一个带可清除障碍的BFS问题,一共就种状态,在队列中维护座标x,y,消除的障碍数k和当前步数step即可。整体时间复杂度为。
class Solution {
public:
int vis[41][41][1601]; // 标记当前状态(x, y, k)是否被访问
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1}; // 四个方向
int shortestPath(vector<vector<int>>& grid, int k) {
int m = grid.size(), n = grid[0].size();
memset(vis, 0, sizeof(vis));
queue<vector<int>> q;
q.push({0, 0, 0, 0}); // {x, y, 已消除的障碍数k, 当前步数step}
vis[0][0][0] = 1;
while(!q.empty())
{
vector<int> now = q.front();
q.pop();
if(now[0]==m-1 && now[1]==n-1) return now[3];
for(int i = 0; i < 4; i++)
{
vector<int> t = now;
int x = t[0]+dx[i], y = t[1]+dy[i];
if(x<0 || x>=m || y<0 || y>=n) continue;
if(grid[x][y]==1) t[2]++;
if(t[2]>k || vis[x][y][t[2]]==1) continue;
vis[x][y][t[2]] = 1;
q.push({x, y, t[2], t[3]+1});
}
}
return -1; // 无法到达
}
};