问题描述
小R手里有一个大小为 n 行 m 列的矩形蛋糕,每个小正方形区域都有一个代表美味度的整数。小R打算切割出一个正方形的小蛋糕给自己,而剩下的部分将给小S。她希望两人吃的部分的美味度之和尽量接近。
我们定义小R吃到的部分的美味度之和为 s_1,而小S吃到的部分的美味度之和为 s_2,请你帮助小R找到一个切割方案,使得 |s_1 - s_2| 的值最小。
解题思路
-
前缀和矩阵:为了快速计算任意正方形区域的美味度之和,我们可以使用前缀和矩阵。前缀和矩阵
prefix_sum的每个元素prefix_sum[i][j]表示从(0, 0)到(i, j)的子矩阵的美味度之和。 -
遍历所有可能的正方形区域:我们需要遍历所有可能的正方形区域,计算每个正方形区域的美味度之和,并计算
|s_1 - s_2|的值。 -
更新最小差值:在遍历过程中,不断更新最小的
|s_1 - s_2|值。
代码人生
def solution(n: int, m: int, a: list) -> int:
# 创建前缀和矩阵
prefix_sum = [[0] * (m + 1) for _ in range(n + 1)]
# 计算前缀和矩阵
for i in range(1, n + 1):
for j in range(1, m + 1):
prefix_sum[i][j] = a[i-1][j-1] + prefix_sum[i-1][j] + prefix_sum[i][j-1] - prefix_sum[i-1][j-1]
min_diff = float('inf')
# 遍历所有可能的正方形区域
for size in range(1, min(n, m) + 1):
for i in range(size, n + 1):
for j in range(size, m + 1):
# 计算正方形区域的美味度之和
s1 = prefix_sum[i][j] - prefix_sum[i-size][j] - prefix_sum[i][j-size] + prefix_sum[i-size][j-size]
s2 = prefix_sum[n][m] - s1
# 计算差值并更新最小差值
min_diff = min(min_diff, abs(s1 - s2))
return min_diff
关键步骤解释
-
前缀和矩阵的计算:
prefix_sum[i][j]表示从(0, 0)到(i, j)的子矩阵的美味度之和。- 通过累加当前元素
a[i-1][j-1]和减去重复计算的部分prefix_sum[i-1][j-1]来计算。
-
遍历所有可能的正方形区域:
- 对于每个可能的正方形大小
size,遍历所有可能的左上角坐标(i, j)。 - 使用前缀和矩阵快速计算正方形区域的美味度之和
s1。
- 对于每个可能的正方形大小
-
计算差值并更新最小差值:
- 计算
s2为整个矩阵的美味度之和减去s1。 - 更新
min_diff为当前差值和之前最小差值中的较小值。
- 计算
测试样例
样例1:
输入:
n = 3, m = 3, a = [[1, 2, 3], [2, 3, 4], [3, 2, 1]]
输出:1
样例2:
输入:
n = 4, m = 4, a = [[1, 2, 3, 4], [4, 3, 2, 1], [1, 2, 3, 4], [4, 3, 2, 1]]
输出:2
样例3:
输入:
n = 2, m = 2, a = [[5, 5], [5, 5]]
输出:10