题目内容:
小包非常喜欢吃甜点,他收到了一次性送来的 NN 个甜点,每个甜点都有一个对应的喜爱值。
但是这还不够!小包让小哥连续送来了 MM 次相同的 NN 个甜点,并将这些甜点首尾相接排成一排。
现在,小包面前有 (N×M)(N×M) 个排成一排的甜点,小包希望从中选择一段连续的甜点,使得这段甜点的总喜爱值最大化。
注意:尽管小包喜欢甜食,但有些甜点可能不合口味,导致其喜爱值为负数。小包至少要选择一个甜点来满足他对甜点的贪心。
输入参数
- 整数 ( N ):表示每次送来的甜点数量。
- 整数 ( M ):表示送来的次数。
- 数组
data:长度为 ( N ),表示每个甜点的喜爱值。
返回结果
- 一个整数,表示在 N×MN×M 个甜点中可以选择的连续甜点段的最大总喜爱值。
测试样例
样例1:
输入:
N = 5 ,M = 1 ,data = [1, 3, -9, 2, 4]
输出:6
解释:选择甜点[2, 4],最大总喜爱值为 6
样例2:
输入:
N = 5 ,M = 3 ,data = [1, 3, -9, 2, 4]
输出:11
解释:排列后甜点为[1, 3, -9, 2, 4, 1, 3, -9, 2, 4, 1, 3, -9, 2, 4]。
选择[2, 4, 1, 3, -9, 2, 4, 1, 3]这段连续甜点,最大总喜爱值为11。
解题思路:
- 甜点序列是周期性的,每个周期包含
N个甜点。 - 需要考虑跨越多个周期的情况。
public static int solution(int N, int M, int[] data) {
// Edit your code here
int max_current = data[0];
int max_global = data[0];
int []d2=new int[N*M];
for(int i=0;i<N*M;i++){
d2[i]=data[i%N];
}
for (int i = 1; i <d2.length; i++) {
max_current = Math.max(d2[i], max_current + d2[i]);
if (max_current > max_global) {
max_global = max_current;
}
}
int total_sum = 0;
for (int sweet : data) {
total_sum += sweet;
}
int result;
if (total_sum > 0) {
result = Math.max(max_global, total_sum * M);
} else {
result = max_global;
}
return result;
}
总结
一开始想的是这会不会是滑动窗口问题,但它会跨越多个周期,因此不是简单的滑动窗口问题。综合来看是最大子数组和问题。具体来说,它结合了以下几种算法和技术:
- Kadane's Algorithm:用于计算单个周期内的最大子数组和。
- 前缀和与后缀和:用于处理跨越多个周期的情况。
- 周期性数组处理:处理多个相同周期的数组拼接问题
上网查阅资料,得出多周期的最大子数组和可以像这样解题:
1.如果 M 为 1,直接返回单个周期的最大子数组和。
2.如果 M 大于 1,需要考虑跨越多个周期的情况。具体来说,可以将问题分解为以下几个部分:
(1)单个周期内的最大子数组和。
(2)跨越多个周期的最大子数组和,可以通过计算前缀和和后缀和来实现。