打家劫舍变形,1388. 3n 块披萨

一、题目

1、题目描述

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

  • 你挑选 任意 一块披萨。
  • Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨。
  • Bob 将会挑选你所选择的披萨顺时针方向的下一块披萨。
  • 重复上述过程直到没有披萨剩下。

每一块披萨的大小按顺时针方向由循环数组 slices 表示。

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

2、接口描述

​python3
class Solution:
    def maxSizeSlices(self, slices: List[int]) -> int:
cpp
class Solution {
public:
    int maxSizeSlices(vector<int>& slices) {

    }
};

3、原题链接

1388. 3n 块披萨


二、解题报告

1、思路分析

我们发现选择一块披萨后,左右相邻的两个就不能选择了,这就跟213. 打家劫舍 II这道经典的题目是类似的

我们定义状态f[i][j]为下标[0, i]的披萨拿了j块的最大总和,那么有状态转移方程:

f[i][j] = max(f[i - 1][j], f[i - 2][j - 1] + slices[i])

方程的含义即拿第i块披萨以及不拿第i块披萨

不拿的话,问题转化为[0, i - 1]中拿j块披萨,拿的话,那就转化为从[0, i - 1]中拿j - 1块的最大总和

由于是环形,对于环形我们通常是倍增,破环成链,但是本题的规则使得我们拿了第0块就拿不了最后一块,拿了最后一块就拿不了第0块,所以在[0, n - 2]的数组上以及[1, n - 1]的数组上跑两次动态规划即可

2、复杂度

时间复杂度: O(n^2)空间复杂度:O(n^2)

3、代码详解

​python3
class Solution:
    def calc(self, a: List[int]) -> int:
        tot, n = len(a), (len(a) + 1) // 3
        dp = [[0] * (n + 1) for _ in range(tot)]
        dp[0][1], dp[1][1] = a[0], max(a[0], a[1])
        for i in range(2, tot):
            for j in range(1, n + 1):
                dp[i][j] = max(dp[i - 1][j], dp[i - 2][j - 1] + a[i])
        return dp[tot - 1][n]
    def maxSizeSlices(self, slices: List[int]) -> int:
        return max(self.calc(slices[1:]), self.calc(slices[0:-1]))
cpp
class Solution {
public:
    int maxSizeSlices(vector<int>& slices) {
        function<int(const vector<int>&)> calc = [&](const vector<int>& a){
            int tot = a.size(), n = (tot + 1) / 3;
            vector<vector<int>> dp(tot, vector<int>(n + 1));
            dp[0][1] = a[0], dp[1][1] = max(a[0], a[1]);
            for(int i = 2; i < tot; i++)
                for(int j = 1; j <= n; j++)
                    dp[i][j] = max(dp[i - 1][j], dp[i - 2][j - 1] + a[i]);
            return dp[tot - 1][n];
        };
        return max(calc(vector<int>(slices.begin(), slices.end() - 1)), calc(vector<int>(slices.begin() + 1, slices.end())));
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值