57题最大相等红包分割问题 | 豆包MarsCode AI刷题

83 阅读3分钟

问题描述

小U在公司年会上运气极佳,赢得了一等奖。作为一等奖得主,他有机会在一排红包中做两次切割,将红包分成三部分,要求第一部分和第三部分的红包总金额相等。他可以获得的金额是第一部分红包的总金额。帮小U计算出他能从这些红包中拿到的最大奖金金额。

解析

该问题的要求就是计算前n项和和后n项和相等的最大数目,而这显然可以用双指针的方式来进行处理。不过这里先说一下另外一种解法,因为在我写完双指针解法后让AI检查代码时他给我的解法。

  • 首先通过前缀和数组 prefix_sum 和后缀和数组 suffix_sum 来存储从左到右的累积和和从右到左的累积和。
  • 然后通过比较前缀和与后缀和来找到一个分割点。具体来说,如果 prefix_sum[i-1] == suffix_sum[i+1],那么说明在该位置可以将红包分为两个和相等的部分。
  • 最后返回最大满足条件的红包总额。

MarsCode AI给出的解法

def solution(redpacks):
    n = len(redpacks)
    if n < 3:
        return 0
    
    # 计算前缀和数组
    prefix_sum = [0] * n
    prefix_sum[0] = redpacks[0]
    for i in range(1, n):
        prefix_sum[i] = prefix_sum[i-1] + redpacks[i]
    
    # 计算后缀和数组
    suffix_sum = [0] * n
    suffix_sum[n-1] = redpacks[n-1]
    for i in range(n-2, -1, -1):
        suffix_sum[i] = suffix_sum[i+1] + redpacks[i]
    
    max_amount = 0
    for i in range(1, n-1):
        if prefix_sum[i-1] == suffix_sum[i+1]:
            max_amount = max(max_amount, prefix_sum[i-1])
    
    return max_amount

这种方法在遍历整个数组时,比较的是 prefix_sum[i-1] 和 suffix_sum[i+1],并且从位置 1 到 n-1 都要遍历一次。虽然这个时间复杂度是 O(n),但不太高效,特别是在给出红包数组非常大的时候。优点是易于理解。

双指针

核心想法是从两端逼近中心,同时计算前n项和和后n项和,直到双指针相遇。

因为我们都知道一个简单的计算b>0时,a+b>a,所以当左边的和小于右边的和时,我们移动左指针。左边和大于 右边和时,我们移动右指针。相等则记录和的值,并同时移动指针。这样直到指针相遇就可以计算出最大的相等红包。

def solution(redpacks):
    # Please write your code here
    idx_left=0
    idx_right=len(redpacks)-1
    sum_left=redpacks[idx_left]
    sum_right=redpacks[idx_right]
    result=0
    while idx_left!=idx_right and idx_left<idx_right:
        if sum_left==sum_right:
            result=sum_left
            idx_left+=1
            idx_right-=1
            sum_left+=redpacks[idx_left]
            sum_right+=redpacks[idx_right]
        elif sum_left<sum_right:
            idx_left+=1
            sum_left+=redpacks[idx_left]
        elif sum_left>sum_right:
            idx_right-=1
            sum_right+=redpacks[idx_right]
    return result

这样我们只需要遍历一遍红包数组,且通过双指针优化了比较的效率,避免了不必要的重复计算。并且不需要开辟额外的数组空间。

总结

数组双指针
时间复杂度O(n)O(n)
时间复杂度O(n)O(1)

所以在以后遇到相似的问题的时候,可以使用双指针来优化运行效率。