小M的蛋糕切割问题题解| 豆包MarsCode AI刷题

116 阅读3分钟

问题描述

小M有一个 n×m 的矩形蛋糕,蛋糕被分为 n×m 个区域,每个区域都有一个美味度。她希望通过一刀将蛋糕切成两部分,一部分自己吃,另一部分给小团。切下的区域必须是完整的,即不能把某个小正方形切成两个小区域。

小M希望两个人吃的部分的美味度之和尽量接近。你的任务是计算出美味度差的最小值,即∣s1-s2∣的最小值,其中s1是小M吃到的美味度,s2是小团吃到的美味度。

解题思路

  1. 前缀和数组:在此题中,使用前缀和数组可以快速计算任意子矩阵的美味度。前缀和数组可以在常数时间内计算任意子矩阵的美味度。
  2. 枚举所有可能的切割方式:运用枚举法,枚举出所有可能的切割方式,包括水平切割和垂直切割。
  3. 计算美味度差:对于每一种切割方式,计算两部分的美味度差,并更新最小值。

代码实现

import java.util.Arrays;
  
public class Main {
    public static int solution(int n, int m, int[][] a) {
        // 创建前缀和数组
        int[][] prefixSum = new int[n + 1][m + 1];
        // 计算前缀和
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                prefixSum[i][j] = a[i - 1][j - 1] + prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1];
            }
        }

        int minDiff = Integer.MAX_VALUE;

        // 枚举所有可能的水平切割
        for (int i = 1; i < n; i++) {
            int s1 = getSubmatrixSum(prefixSum, 0, 0, i, m);
            int s2 = getSubmatrixSum(prefixSum, i, 0, n, m);
            minDiff = Math.min(minDiff, Math.abs(s1 - s2));
        }

        // 枚举所有可能的垂直切割
        for (int j = 1; j < m; j++) {
            int s1 = getSubmatrixSum(prefixSum, 0, 0, n, j);
            int s2 = getSubmatrixSum(prefixSum, 0, j, n, m);
            minDiff = Math.min(minDiff, Math.abs(s1 - s2));
        }

        return minDiff;
    }

    // 计算子矩阵的美味度
    private static int getSubmatrixSum(int[][] prefixSum, int x1, int y1, int x2, int y2) {
        return prefixSum[x2][y2] - prefixSum[x1][y2] - prefixSum[x2][y1] + prefixSum[x1][y1];
    }


    public static void main(String[] args) {
        System.out.println(solution(2, 3, new int[][]{{1, 1, 4}, {5, 1, 4}}) == 0);
        System.out.println(solution(3, 3, new int[][]{{3, 2, 1}, {4, 5, 6}, {7, 8, 9}}) == 3);
        System.out.println(solution(2, 2, new int[][]{{1, 2}, {3, 4}}) == 2);
    }
}

代码说明

  1. 前缀和数组prefixSum[i][j] 表示从 (0, 0) 到 (i, j) 的子矩阵的美味度之和。

  2. 计算前缀和:通过遍历原始矩阵 a,我们可以逐步构建前缀和数组。具体来说,对于每个位置 (i, j),可以通过以下公式计算前缀和:

    prefixSum[i][j] = a[i-1][j-1] + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1]

    这里,a[i-1][j-1] 是当前位置的美味度,prefixSum[i-1][j] 是上方子矩阵的美味度,prefixSum[i][j-1] 是左方子矩阵的美味度,prefixSum[i-1][j-1] 是左上角子矩阵的美味度。

  3. 计算总美味度:矩形蛋糕的总美味度就是 prefixSum[n][m],其中 n 和 m 分别是矩阵的行数和列数。

复杂度分析

1. 时间复杂度 :在这个问题中,前缀和数组的构建和查询操作的时间复杂度都是 O(1),因此整个算法的时间复杂度是 O(n * m),其中 n 和 m 分别是矩阵的行数和列数。

2. 空间复杂度 :在这个问题中,使用了一个额外的二维数组来存储前缀和,因此空间复杂度是 O(n * m)。

总结

通过对此题的练习,我对如何运用前缀和有了更深的了解,通过构建前缀和数组,可以在常数时间内计算任意子区间的和。同时我还学到了如何处理边界条件,在构建前缀和数组时确保数组的索引不会越界。并且对如何访问和操作二维数组的元素也更加熟练。