用邮票贴满网格图
力扣链接
解题思路
大佬题解
解题前提: 需要知道二维前缀和与二维差分
- 二维前缀和 + 二维差分
代码
class Solution {
public boolean possibleToStamp(int[][] grid, int h, int w) {
int m = grid.length;
int n = grid[0].length;
//二维前缀和
int[][] sum = new int[m + 1][n + 1];
//二维差分
int[][] diff = new int[m + 1][n + 1];
//遍历求前缀和
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
//二维前缀和计算公式
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] + grid[i - 1][j - 1] - sum[i - 1][j - 1];
}
}
//对所有能容纳邮票大小的空格进行范围+1操作
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
//从左上角坐标为0中寻找能容纳邮票的二维区域
if (grid[i][j] == 0) {
int x = i + h;
int y = j + w;
//如果x,y在边界内,且由左上角[i,j]和右下角[x - 1, y - 1]围成的区域和为0,则说明该区域可以放置邮票,进行区域+1操作
if (x <= m && y <= n && (sum[x][y] + sum[i][j] - sum[i][y] - sum[x][j] == 0)) {
++diff[i][j];
++diff[x][y];
--diff[i][y];
--diff[x][j];
}
}
}
}
//还原二维差分矩阵对应的计数矩阵,这里用滚动数组实现
int[] pre = new int[n + 1];
int[] cur = new int[n + 1];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
cur[j + 1] = diff[i][j] + cur[j] + pre[j + 1] - pre[j];
//如果某一个格的数组原值为0,差分数组的前缀和也为0,则说明该格未被邮票覆盖,返回false
if (cur[j + 1] == 0 && grid[i][j] == 0) {
return false;
}
}
int[] tmp = cur;
cur = pre;
pre = tmp;
}
return true;
}
}
复杂度
- 时间复杂度: O(mn)
- 空间复杂度: O(mn)