第一題直接模擬,第二題可以手動打表。
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; // 無法到達
}
};