差分数组
1 2 3 4
| a[0] a[1] a[2] a[3] a[4] (0) 差分数组: a[0] a[1]-a[0] a[2]-a[1] a[3]-a[2] a[4]-a[3] (-a[4]) 对差分数组求前缀和: a[0] a[1] a[2] a[3] a[4] (0)
|
前缀和就是离散版本的“求积分”,差分数组就是离散版本的“求微分”
给你一个整数数组 target
和一个数组 initial
,initial
数组与 target
数组有同样的维度,且一开始全部为 0 。
请你返回从 initial
得到 target
的最少操作次数,每次操作需遵循以下规则:
- 在
initial
中选择 任意 子数组,并将子数组中每个元素增加 1 。
答案保证在 32 位有符号整数以内。
示例 1:
1 2 3 4 5 6 7
| 输入:target = [1,2,3,2,1] 输出:3 解释:我们需要至少 3 次操作从 intial 数组得到 target 数组。 [0,0,0,0,0] 将下标为 0 到 4 的元素(包含二者)加 1 。 [1,1,1,1,1] 将下标为 1 到 3 的元素(包含二者)加 1 。 [1,2,2,2,1] 将下表为 2 的元素增加 1 。 [1,2,3,2,1] 得到了目标数组。
|
示例 2:
1 2 3
| 输入:target = [3,1,1,2] 输出:4 解释:(initial)[0,0,0,0] -> [1,1,1,1] -> [1,1,1,2] -> [2,1,1,2] -> [3,1,1,2] (target) 。
|
示例 3:
1 2 3 4
| 输入:target = [3,1,5,4,2] 输出:7 解释:(initial)[0,0,0,0,0] -> [1,1,1,1,1] -> [2,1,1,1,1] -> [3,1,1,1,1] -> [3,1,2,2,2] -> [3,1,3,3,2] -> [3,1,4,4,2] -> [3,1,5,4,2] (target)。
|
示例 4:
1 2
| 输入:target = [1,1,1,1] 输出:1
|
提示:
1 <= target.length <= 10^5
1 <= target[i] <= 10^5
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public int minNumberOperations(int[] target) { int n = target.length, d[] = new int[n+1], res = 0; d[0] = target[0]; for (int i = 1; i < n; i++) { d[i] = target[i] - target[i-1]; } d[n] = -target[n-1]; for (int dd : d) { if (dd > 0) res += dd; } return res; } }
|
给你两个长度相同的正整数数组 nums
和 target
。
在一次操作中,你可以选择 nums
的任何
子数组
,并将该子数组内的每个元素的值增加或减少 1。
返回使 nums
数组变为 target
数组所需的 最少 操作次数。
示例 1:
输入: nums = [3,5,1,2], target = [4,6,2,4]
输出: 2
解释:
执行以下操作可以使 nums
等于 target
:
- nums[0..3]
增加 1,nums = [4,6,2,3]
。
- nums[3..3]
增加 1,nums = [4,6,2,4]
。
示例 2:
输入: nums = [1,3,2], target = [2,1,4]
输出: 5
解释:
执行以下操作可以使 nums
等于 target
:
- nums[0..0]
增加 1,nums = [2,3,2]
。
- nums[1..1]
减少 1,nums = [2,2,2]
。
- nums[1..1]
减少 1,nums = [2,1,2]
。
- nums[2..2]
增加 1,nums = [2,1,3]
。
- nums[2..2]
增加 1,nums = [2,1,4]
。
提示:
1 <= nums.length == target.length <= 10^5
1 <= nums[i], target[i] <= 10^8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public long minimumOperations(int[] nums, int[] target) { int n = target.length, diff[] = new int[n], d[] = new int[n+1]; long res = 0; for (int i = 0; i < n; i++) diff[i] = nums[i] - target[i]; d[0] = diff[0]; for (int i = 1; i < n; i++) { d[i] = diff[i] - diff[i-1]; } d[n] = -diff[n-1]; for (int dd : d) { if (dd > 0) res += dd; } return res; } }
|
二维差分数组
假设对于原矩阵,给一个左上角grid[l][u]
,右下角grid[r][d]
的子矩阵的元素都添加一
那么对于差分数组diff[][]
来说,相当于:
1 2 3 4 5 6
|
diff[l][u]++; diff[r+1][u]--; diff[l][d+1]--; diff[r+1][d+1]++;
|
比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 0 0
|
给你一个 m x n
的二进制矩阵 grid
,每个格子要么为 0
(空)要么为 1
(被占据)。
给你邮票的尺寸为 stampHeight x stampWidth
。我们想将邮票贴进二进制矩阵中,且满足以下 限制 和 要求 :
- 覆盖所有 空 格子。
- 不覆盖任何 被占据 的格子。
- 我们可以放入任意数目的邮票。
- 邮票可以相互有 重叠 部分。
- 邮票不允许 旋转 。
- 邮票必须完全在矩阵 内 。
如果在满足上述要求的前提下,可以放入邮票,请返回 true
,否则返回 false
。
示例 1:
1 2 3
| 输入:grid = [[1,0,0,0],[1,0,0,0],[1,0,0,0],[1,0,0,0],[1,0,0,0]], stampHeight = 4, stampWidth = 3 输出:true 解释:我们放入两个有重叠部分的邮票(图中标号为 1 和 2),它们能覆盖所有与空格子。
|
示例 2:
1 2 3
| 输入:grid = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]], stampHeight = 2, stampWidth = 2 输出:false 解释:没办法放入邮票覆盖所有的空格子,且邮票不超出网格图以外。
|
提示:
m == grid.length
n == grid[r].length
1 <= m, n <= 10^5
1 <= m * n <= 2 * 10^5
grid[r][c]
要么是 0
,要么是 1
。
1 <= stampHeight, stampWidth <= 10^5
二维前缀和+二维差分数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { public boolean possibleToStamp(int[][] grid, int stampHeight, int stampWidth) { int m = grid.length, n = grid[0].length, sum[][] = new int[m+1][n+1], diff[][] = new int[m+2][n+2]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { sum[i+1][j+1] = grid[i][j] + sum[i+1][j] + sum[i][j+1] - sum[i][j]; } } for (int i = 0; i < m - stampHeight + 1; i++) { for (int j = 0; j < n - stampWidth + 1; j++) { int l = i, r = i+stampHeight, u = j, d = j+stampWidth; if (sum[r][d] - sum[l][d] - sum[r][u] + sum[l][u] == 0) { diff[l+1][u+1]++; diff[r+1][u+1]--; diff[l+1][d+1]--; diff[r+1][d+1]++; } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { diff[i+1][j+1] += diff[i+1][j] + diff[i][j+1] - diff[i][j]; if (grid[i][j] == 0 && diff[i+1][j+1] == 0) return false; } } return true; } }
|