给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨:
每一块披萨的大小按顺时针方向由循环数组 slices
表示。
请你返回你可以获得的披萨大小总和的最大值。
1 < = s l i c e s . l e n g t h < = 500 s l i c e s . l e n g t h 1 < = s l i c e s [ i ] < = 1000 1 <= slices.length <= 500\\ slices.length % 3 == 0\\ 1 <= slices[i] <= 1000 1<=slices.length<=500slices.length1<=slices[i]<=1000
今天的pizz 比较hard。
这个圆形的pizza,每一块都有编号,而且每一块的大小不一样。 这里用了一个一维数组来表示这个pizza。
步骤
它要求每次user可以先选一块,然后AB会选user选择的相邻的2块。
每次操作就会减少3块,一共可以进行n次。
要计算出user可以选择的pizza的总和最大。
也就是说一定会存在某个方法,可以使user的在n次操作后,可以得到的pizza大小累加最大。
一般这样,都会想到用递归枚举来做,如果按照昨天的每日pizza问题的递归思路是无法解决的,具体的可以尝试。
转换思路
这个问题,还是比较难想的,如果之前有见过 house robber问题的,可能比较容易理解。
该问题对应的模型,其实近似于在前3n个数中,选择n个不相邻的数,可以得到的最大和。
也就是说,所有方案中user选择的数字一定都是间隔的,特别需要强调的是这里是环形的,所以需要处理首尾的2个元素被选中的方案。
思路
到此,需要解决的就是如何在前i个数字中选出j个不相邻的元素的最大值。
使用 d f s ( i , j ) dfs(i,j) dfs(i,j)来表示这个递归。
其子问题可以分解为,
所以 d f s ( i , j ) = m a x ( d f s ( i − 2 , j − 1 ) + a [ i ] , d f s ( i − 1 , j ) ) dfs(i,j) = max( dfs(i-2,j-1)+ a[i],dfs(i-1,j)) dfs(i,j)=max(dfs(i−2,j−1)+a[i],dfs(i−1,j))
到此基于非环形的pizza,就可以了,这里会出现一个比较特殊的情况,即第0个被选中,第n-1个也被选中时的得分最大,也是符合这个递归要求的。
但是这个情况并不符合问题的要求,在环形的情况下2个元素相邻了。
为了避免这个问题,做一下调节即可,先计算 0 → n − 2 0\rightarrow n-2 0→n−2 区间的最大和,此时一定不会出现首尾相邻,然后计算 1 → n − 1 1\rightarrow n-1 1→n−1,此时也是符合要求的。
到此整个问题就可以AC了。
class Solution {
int INF;
int[][] memo;
public int maxSizeSlices(int[] slices) {
int n = slices.length;
int[] s1 = new int[n-1];//0~n-2
int[] s2 = new int[n-1];//1~n-1
for(int i= 1;i<n;i++){
s1[i-1] = slices[i-1];
s2[i-1] = slices[i];
}
INF = Integer.MIN_VALUE/2;
int cnt = n/3;
memo = new int[n][cnt+1];
for(int i = 0;i<n;i++){
Arrays.fill(memo[i],-1);
}
int res = dfs(n-1,cnt,s1);
for(int i = 0;i<n;i++){
Arrays.fill(memo[i],-1);
}
res = Math.max(res,dfs(n-1,cnt,s2));
return res;
}
public int dfs(int idx,int cnt,int[] s){
if(memo[idx][cnt]!=-1){
return memo[idx][cnt];
}
if(cnt==0||idx<3){
//cnt==0 idx = any
if(cnt==0) return 0;
// cnt ==any idx<3
//cnt==1 idx <3
if(cnt==1){
return idx==1?s[0]:Math.max(s[0],s[1]);
}
// cnt >1 idx<3
return memo[idx][cnt] = INF;
}
// idx>=3 && cnt>0
int res =dfs(idx-2,cnt-1,s)+s[idx-1];
res = Math.max(res,dfs(idx-1,cnt,s));
return memo[idx][cnt] = res;
}
}
时间复杂度 O ( N 2 ) O(N^2) O(N2)
空间复杂度 O ( N 2 ) O(N^2) O(N2)
Array
Memoization