题号102 贪心的小包
问题描述
小包非常喜欢吃甜点,他收到了一次性送来的 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。
问题理解
- 甜点排列:题目中提到甜点被连续送来了
M次,每次送来的甜点数量为N。这意味着甜点的总数是N * M。 - 连续子数组的最大和:我们需要找到一个连续的子数组,使得这个子数组的总喜爱值最大。
数据结构与算法选择
-
最大子数组和问题:这是一个经典的动态规划问题,通常可以使用 Kadane 算法来解决。Kadane 算法的时间复杂度是
O(n),其中n是数组的长度。 -
重复数组的影响:由于甜点是重复的,我们需要考虑如何处理这些重复的甜点。我们可以将问题分解为以下几个步骤:
- 计算单个
data数组的最大子数组和。 - 计算整个
N * M数组的最大子数组和。
- 计算单个
算法步骤
-
计算单个
data数组的最大子数组和:使用 Kadane 算法计算data数组的最大子数组和。 -
计算整个
N * M数组的最大子数组和:-
如果
M == 1,直接返回单个data数组的最大子数组和。 -
如果
M > 1,我们需要考虑跨越多段data数组的情况。我们可以通过以下方式处理:- 计算
data数组的总和。 - 计算
data数组的最大前缀和和最大后缀和。 - 计算跨越多段
data数组的最大子数组和。
- 计算
-
-
综合考虑:将上述结果综合考虑,得到最终的最大子数组和。
总结
通过上述步骤,我们可以有效地解决这个问题。关键在于理解如何处理重复的 data 数组,并结合 Kadane 算法来计算最大子数组和。
代码实现
def solution(N, M, data):
# Step 1: Calculate total sums
total_sum = sum(data)
# Step 2: Use Kadane's algorithm to find the maximum subarray sum
def kadane(arr):
max_ending_here = max_so_far = arr[0]
for x in arr[1:]:
max_ending_here = max(x, max_ending_here + x)
max_so_far = max(max_so_far, max_ending_here)
return max_so_far
# Maximum sum for a single segment of sweets
max_single = kadane(data)
# If M = 1, return that value
if M == 1:
return max_single
# Step 3: Try to combine segments across boundaries
# Prefix sums
prefix_sum = [0] * N
prefix_sum[0] = data[0]
for i in range(1, N):
prefix_sum[i] = prefix_sum[i-1] + data[i]
# Suffix sums
suffix_sum = [0] * N
suffix_sum[N-1] = data[N-1]
for i in range(N-2, -1, -1):
suffix_sum[i] = suffix_sum[i+1] + data[i]
# Maximum prefix sum
max_prefix = max(prefix_sum)
# Maximum suffix sum
max_suffix = max(suffix_sum)
# Maximum result combining prefix, one full N segment, and suffix
if total_sum > 0:
# If total sum is positive, we can take full M-2 full arrays in between
max_combination = max_prefix + max_suffix + (M - 2) * total_sum
else:
# If total sum is non-positive, just take the max of prefix and suffix combination
max_combination = max_prefix + max_suffix
# Step 4: Compare max_combination with max_single
return max(max_single, max_combination)
# Sample test cases:
print(solution(5, 1, [1, 3, -9, 2, 4])) # Output: 6
print(solution(5, 3, [1, 3, -9, 2, 4])) # Output: 11
解释
- Kadane’s Algorithm:找到了在一次 N 个甜点中可能获得的最大连续合计值。
- 前缀和与后缀和:计算出最大前缀和和后缀和,以便计算跨越中的最大和。
- 总和处理:检查 M 并根据总的喜爱值处理跨越边界的情况,最终返回全局最大的值。
复杂度
- 时间复杂度为 O(N) 因为我们仅需对数据数组进行常数次遍历。
- 空间复杂度为 O(N) 用于存储前缀和和后缀和的数组。
我们就成功通过了本题🤩
本次我们通过《贪心的小包》这道题目的解决过程展示了豆包MarsCode AI刷题平台的几个显著亮点:
- 算法推荐与指导:当用户在解决问题时遇到瓶颈,例如不知道如何有效统计特定范围内的二进制数中1的个数之和时,AI能够提供具体的算法建议,并给出详细的算法流程、伪代码及实现代码,极大地降低了学习和解决问题的门槛。
- 多语言支持与代码转换:虽然豆包MarsCode AI刷题平台可能最初只提供了某些编程语言的支持,但它具备强大的跨语言代码转换功能,可以将用户的C++代码转换成Java或Python等其他语言的等效代码。这一特性对于那些需要在不同语言环境间切换的开发者来说非常有用,确保了用户能够在任何平台上顺利提交解决方案。
- 实践性与即时反馈:通过实际编写代码并测试示例输入输出,用户可以在提交之前验证自己的解答是否正确。这种即时的反馈机制有助于加深理解,及时调整错误,提高学习效率。 通过豆包MarsCode AI刷题平台,我们可以看到AI刷题的强大之处,它不仅向我们提供思路提示,更给我们提供代码框架,我们需要做的就是往框架里面填写代码并添加一些自己的思考,这极大程度地提高了我们编写代码的效率,同时也拓宽了我们编写代码的思路。跟随AI刷题的步伐,我们的写代码的能力也会越来越强。豆包MarsCode AI刷题工具通过精选真题与个性化推荐功能,帮助我高效地掌握了复杂的算法知识,也提升了我的自学能力,是我学习过程中的得力助手。 综上所述,豆包MarsCode AI刷题平台具有精准的算法指导、灵活的多语言支持以及即时的实践反馈,为用户提供了一个高效、便捷且富有成效的学习环境。
好了,那么我们这一次的解析就到这里,后面会给大家展示豆包MarsCode AI刷题的更多功能