Leetcode 1388. 3n 块披萨

发布时间 2023-08-18 19:15:42作者: 无聊的飞熊

(本文只提供了解题思路的思考,原文作者题解连接)
先把题目粘贴在这里

给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨:

你挑选 任意 一块披萨。
Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨。
Bob 将会挑选你所选择的披萨顺时针方向的下一块披萨。
重复上述过程直到没有披萨剩下。
每一块披萨的大小按顺时针方向由循环数组 slices 表示。

请你返回你可以获得的披萨大小总和的最大值。

输入:slices = [1,2,3,4,5,6]
输出:10
解释:选择大小为 4 的披萨,Alice 和 Bob 分别挑选大小为 3 和 5 的披萨。然后你选择大小为 6 的披萨,Alice 和 Bob 分别挑选大小为 2 和 1 的披萨。你获得的披萨总大小为 4 + 6 = 10 。


输入:slices = [8,9,8,6,1,1]
输出:16
解释:两轮都选大小为 8 的披萨。如果你选择大小为 9 的披萨,你的朋友们就会选择大小为 8 的披萨,这种情况下你的总和不是最大的。

提示:

  • 1 <= slices.length <= 500
  • slices.length % 3 == 0
  • 1 <= slices[i] <= 1000
class Solution {
    public int maxSizeSlices(int[] slices) {
        if (slices == null || slices.length == 0) return 0;
        if (slices.length == 1) return slices[0];
        if (slices.length == 2) return Math.max(slices[0], slices[1]);

        int len = slices.length;
        int n = len / 3;
        return Math.max(maxTakebyRange(slices, 0, len - 2, n), maxTakebyRange(slices, 1, len - 1, n));

    }

    private int maxTakebyRange(int[] slices, int start, int end, int n) {
        if (start == end) return slices[start];
        int len = end - start + 1;

        //dp[i][j] = the max size we can get, range: [0, i], picked count: j
        int[][] dp = new int[len][n + 1];

        //base condition
        dp[0][0] = 0;
        dp[0][1] = slices[start];
        dp[1][0] = 0;
        dp[1][1] = Math.max(slices[start], slices[start + 1]);

        //dp transfer
        for (int i = 2; i < len; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = Math.max(dp[i - 2][j - 1] + slices[start + i], dp[i - 1][j]);
            }
        }

        return dp[len - 1][n];
    }
}

接下来是我对于此代码的理解:
先把前几种情况写出
第一种情况:数组为空,返回0;
第二种情况:数组长度为1,返回数组首元素;
第三种情况:数组长度为2,返回数组两元素最大值
再将数组长度定义为len,n定义为可以选几次

接下来就是动态规划的部分,但我算法基础比较弱,所以对此理解得不深,希望有大神可以指导我

开始也是头等于尾的情况,直接返回头
这里又再次定义了一个长度len=end-start+1,结果和上面定义的slices.length应该是相同的,那为什么没有直接引用上述呢,哦!!!对,这段代码是不同start的,所以长度不一定相同
接下来就准备开始进行dp了
定义了dp[len][n+1],长度和slices.length/3+1,这里又是为何如此设置呢?
我来举个例子看看我能不能搞明白,
slices 1 2 3 4 5 6 7
下标 0 1 2 3 4 5 6
start=0 时,len=7,n=int(7/3)=2,dp[len][n+1]=dp[7][3]
start=1 时,len=6,n=int(6/3)=2,dp[len][n+1]=dp[6][3]
看起来是为了让选择次数相等。

之后更新了基础条件,以供后面的遍历使用
dp[0][0] = 0 表示在范围 [0, 0] 内不选择切片,所以最大切片大小为0;
dp[0][1] = slices[start] 表示在范围 [0, 0] 内选择一个切片,所以最大切片大小为 slices[start];
dp[1][0] = 0 表示在范围 [0, 1] 内不选择切片,所以最大切片大小为0;
dp[1][1] = max(slices[start], slices[start + 1]) 表示在范围 [0, 1] 内选择一个切片,所以最大切片大小为 slices[start] 和 slices[start + 1] 中的最大值。

接下来,使用双重循环来计算动态规划的转移方程。外层循环从2开始,内层循环从1开始。循环变量 i 表示当前的范围终止索引,循环变量 j 表示当前选择的切片数量。
在每次循环中,通过对比两种选择:选择当前切片和不选择当前切片,来更新 dp[i][j] 的值。动态转移方程为:
dp[i][j] = max(dp[i - 2][j - 1] + slices[start + i], dp[i - 1][j])
其中,dp[i - 2][j - 1] + slices[start + i] 表示选择当前切片,dp[i - 1][j] 表示不选择当前切片。
最后,返回 dp[len - 1][n],即在整个范围内选择 n 个切片时的最大切片大小。