3n 块披萨【LC1388】
给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨:
- 你挑选 任意 一块披萨。
- Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨。
- Bob 将会挑选你所选择的披萨顺时针方向的下一块披萨。
- 重复上述过程直到没有披萨剩下。
每一块披萨的大小按顺时针方向由循环数组
slices
表示。请你返回你可以获得的披萨大小总和的最大值。
没想出来转化,正好复习一下打家劫舍
-
思路
-
该问题可以转化为在环形数组
slices
中取不相邻的 k k k个数,求最大和。【数学归纳法证明可得,也可以通过观察得到】 -
环形数组与普通数组的区别在于,首尾元素不能同时取,因此可以进行2次dp
-
确定dp数组(dp table)以及下标的含义
d p [ i ] [ j ] dp[i][j] dp[i][j]:表示在数组 nums 的前 i i i 个数中选择 j j j 个不相邻的数的最大和。。
-
确定递推公式
- 取第 i i i个数: d p [ i ] [ j ] = d p [ i − 2 ] [ j − 1 ] + n u m s [ i ] dp[i][j] = dp[i-2][j-1] + nums[i] dp[i][j]=dp[i−2][j−1]+nums[i]
- 不取第 i i i个数: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i−1][j]
d p [ i ] [ j ] = m a x ( d p [ i − 2 ] [ j − 1 ] + n u m s [ i ] , d p [ i − 1 ] [ j ] ) dp[i][j] =max( dp[i-2][j-1] + nums[i], dp[i-1][j]) dp[i][j]=max(dp[i−2][j−1]+nums[i],dp[i−1][j])
-
dp数组如何初始化
dp[0][1] = nums[0]; dp[1][1] = Math.max(nums[0],nums[1]);
-
确定遍历顺序
从前往后遍历
nums
,枚举 j j j
-
-
实现
class Solution { public int maxSizeSlices(int[] slices) { int n = slices.length; int a = f(slices, 0, n - 2); int b = f(slices, 1, n - 1); return Math.max(a, b); } public int f(int[] nums, int start, int end){ int n = nums.length, k = n / 3; int[][] dp = new int[n][k + 1]; dp[start][1] = nums[start]; dp[start + 1][1] = Math.max(nums[start], nums[start + 1]); for (int i = start + 2; i <= end; i++){ for (int j = 1; j <= k; j++){ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 2][j - 1] + nums[i]); } } return dp[end][k]; } }
-
复杂度
时间复杂度: O ( n k ) O(nk) O(nk)
空间复杂度: O ( n k ) O(nk) O(nk)
-