这题写了好久,一开始掉一个坑里面没出来。
我一开始想的是列举邮贴的左上角贴在每个格子的情况,提前计算出前缀和判断是否可贴,可贴的话就把贴的那块区域全部都赋值为已访问。往后遍历的时候,已访问过的就不再考虑它作为左上角的情况,这样应该不会超时。并没有想到采用延迟更新。
结果样例都没过,然后对着样例发现没有考虑每个格子作为其他三个角的情况,然后补成了每个格子作为四个角的情况,结果样例过了,交上去过了60+,wa了。
然后静下心来再想了想,想到了正解。写第一个解法浪费了太多时间。
怎么说呢,也不知道为什么,都已经想到前缀和了,咋一开始就没想到前缀和搭配的延迟更新呢?咳!可能是因为之前没有写过二维的延迟更新吧,所以反应没有那么快。
想到了延迟更新就好办了,不清楚一维数组延迟更新的方法的自行搜索吧,这里给出二维数组延迟更新的方法:
比方说要给阴影区域每个格子都加1,那么需要给以下四个格子标记,最后延迟更新完事。
代码如下:
typedef long long ll;
class Solution {
public:
bool possibleToStamp(vector<vector<int>>& grid, int stampHeight, int stampWidth) {
int n=grid.size();
int m=grid[0].size();
vector<vector<int>> A;
vector<vector<int>> B;
vector<vector<int>> C;
for(int i=0;i<n;i++) A.push_back(vector<int>()),B.push_back(vector<int>()),C.push_back(vector<int>());
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
A[i].push_back(grid[i][j]^1);
if(i==0&&j!=0) A[i][j]+=A[i][j-1];
else if(i!=0&&j==0) A[i][j]+=A[i-1][j];
else if(i!=0&&j!=0) A[i][j]+=(A[i-1][j]+A[i][j-1]-A[i-1][j-1]);
B[i].push_back(grid[i][j]);
C[i].push_back(0);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(B[i][j]==0)
{
int x=i+stampHeight-1,y=j+stampWidth-1;
if(x<n&&y<m)
{
int sum=A[x][y];
if(i==0&&j!=0) sum-=A[x][j-1];
else if(i!=0&&j==0) sum-=A[i-1][y];
else if(i!=0&&j!=0) sum-=(A[i-1][y]+A[x][j-1]-A[i-1][j-1]);
if(sum==stampHeight*stampWidth)
{
C[i][j]+=1;
if(x+1<n&&y+1>=m) C[x+1][j]-=1;
else if(x+1>=n&&y+1<m) C[i][y+1]-=1;
else if(x+1<n&&y+1<m) C[x+1][j]-=1,C[i][y+1]-=1,C[x+1][y+1]+=1;
}
}
}
}
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==0&&j!=0) C[i][j]+=C[i][j-1];
else if(i!=0&&j==0) C[i][j]+=C[i-1][j];
else if(i!=0&&j!=0) C[i][j]+=(C[i-1][j]+C[i][j-1]-C[i-1][j-1]);
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(grid[i][j]==0&&C[i][j]==0) return false;
return true;
}
};
最后想了一段时间才想出我第一个解法的问题:
对于下图的情况,按照我第一个解法,那么中间那块区域是不可能被覆盖的,但实际上是可以被填充的。就错了。