1.题目
问题描述
小M有一个 n×mn×m 的矩形蛋糕,蛋糕被分为 n×mn×m 个区域,每个区域都有一个美味度。她希望通过一刀将蛋糕切成两部分,一部分自己吃,另一部分给小团。切下的区域必须是完整的,即不能把某个小正方形切成两个小区域。
小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即 ∣s1−s2∣∣s1−s2∣ 的最小值,其中 s1s1 是小M吃到的美味度,s2s2 是小团吃到的美味度。
测试样例
样例1:
输入:n = 2, m = 3, a = [[1, 1, 4], [5, 1, 4]]
输出:
0
样例2:
输入:n = 3, m = 3, a = [[3, 2, 1], [4, 5, 6], [7, 8, 9]]
输出:
3
样例3:
输入:n = 2, m = 2, a = [[1, 2], [3, 4]]
输出:
2
2.思路
切割只能竖直切割或水平切割,遍历所有切割线,采用前缀和求出两块的美味度,找到美味度差的最小值
3.代码
def solution(n: int, m: int, a: list) -> int:
# PLEASE DO NOT MODIFY THE FUNCTION SIGNATURE
# write code here
assert n == len(a) and m == len(a[0])
# 设置一个较大的常数 N,确保数组大小足够容纳 n 和 m 的值
N = 1024
ax = [0] * N # ax 用于存储每一行的美味度总和
ay = [0] * N # ay 用于存储每一列的美味度总和
sx = [0] * N # sx 用于存储前缀和,即从第 1 行到第 i 行的累积美味度和
sy = [0] * N # sy 用于存储前缀和,即从第 1 列到第 j 列的累积美味度和
# 遍历矩阵 a,计算每一行的美味度总和,存入 ax;每一列的美味度总和,存入 ay
for i in range(1, n + 1):
for j in range(1, m + 1):
ax[i] += a[i - 1][j - 1] # 将第 i 行第 j 列的美味度加到 ax[i] 中
ay[j] += a[i - 1][j - 1] # 将第 i 行第 j 列的美味度加到 ay[j] 中
# 计算每行的前缀和,将结果存入 sx 数组中
for i in range(1, n + 1):
sx[i] = sx[i - 1] + ax[i] # sx[i] 为前 i 行的累积美味度和
# 计算每列的前缀和,将结果存入 sy 数组中
for j in range(1, m + 1):
sy[j] = sy[j - 1] + ay[j]
# 初始化答案 ans 为所有行的美味度总和(即 sx[n])
ans = sx[n]
# 遍历每一行,计算切割后的两部分美味度和的绝对差值,并寻找最小的差值
for i in range(n):
ans = min(ans, abs(sx[i] - (sx[n] - sx[i])))
# 遍历每一列,计算切割后的两部分美味度和的绝对差值,并寻找最小的差值
for j in range(m):
ans = min(ans, abs(sy[j] - (sy[m] - sy[j])))
return ans
if __name__ == '__main__':
print(solution(2, 3, [[1, 1, 4], [5, 1, 4]]) == 0)
print(solution(3, 3, [[3, 2, 1], [4, 5, 6], [7, 8, 9]]) == 3)
print(solution(2, 2, [[1, 2], [3, 4]]) == 2)
4.总结
前缀和算是思路不难,但很容易错的一类题型,前缀和数组往往下标从1开始,在下标处要格外注意,时时画图。同时,这道题有四个数组ax,ay,sx,sy,很容易写错,开始时我便将每一列的美味度总和误加到ax中,第一次排错都没有发现,需要格外细心。