修改数组求最大和问题解题思路 | 豆包MarsCode AI刷题

42 阅读4分钟

题目

小U有一个整数数组 nums 和一个整数 k。他可以执行以下操作恰好 k 次:选择某个下标 i 并将 nums[i] 替换为 -nums[i]。同一个下标 i 可以被多次选择进行操作。

小U想知道,通过这种方式修改数组后,能够得到的数组可能的最大和是多少。

解题思路

  1. 操作的效果

    • 每次选择一个下标 i,将 nums[i] 替换为 -nums[i]。这样可以将负数变为正数,或者将正数变为负数。
    • 目标是最大化数组的和,因此显然我们应尽量将负数变为正数。
  2. 最优操作顺序

    • 首先应对数组中的 负数 进行操作,将它们变为正数,以增加数组的和。
    • 如果 k 次操作后还有剩余的操作次数(即 k 没有完全消耗),可以考虑将某些已经是正数的元素再次取反。对于已经是正数的元素,再取反会减少和,因此尽量减少这种操作。
  3. 操作步骤

    • 第一步:先对所有负数进行操作,尽可能将它们变为正数。
    • 第二步:如果还有剩余的操作次数,且剩余的操作次数为奇数,则选择最小的绝对值进行再次取反,因为最小的绝对值带来的损失最小。
  4. 排序的使用

    • 可以将数组中的元素按绝对值大小排序,这样我们可以优先选择绝对值较大的元素进行操作,以便最大化总和。

豆包MarsCode AI针对我们的思路补充

1. 操作的效果:

每次操作的核心是将数组中的某个元素 nums[i] 取负,即变成 -nums[i]。这会导致:

  • 如果该元素是负数,取负后变为正数,数组的总和增加。
  • 如果该元素是正数,取负后变为负数,数组的总和减少。

因此,我们希望尽量选择将负数变为正数,因为这会增加数组的总和。

2. 操作的优先级:

我们需要根据每个操作对数组总和的影响来决定操作顺序。最优策略是:

  • 优先处理负数:  负数取负后会变为正数,从而增加数组的总和。所以,我们优先将负数变为正数。
  • 然后处理正数:  如果操作次数 k 还剩余,且所有负数都已经处理完,剩下的操作可能会对正数产生影响。我们应该选择绝对值最小的元素进行反转,因为反转绝对值最小的元素对总和的影响最小。

3. 如何决定操作顺序:

我们可以通过以下步骤来决定最优的操作顺序:

  • 第一步:排序:将数组按照元素的 绝对值 排序,优先处理绝对值大的元素。这样可以确保我们对影响最大的元素进行反转,从而尽可能最大化数组的和。
  • 第二步:执行反转操作:从排序后的数组中选择元素进行反转。首先反转负数,将它们变为正数。每次反转一个负数时,k 减少1。
  • 第三步:剩余操作处理:如果 k 还有剩余,且 k 为奇数(即剩余的操作次数为奇数),我们就要对剩下的最小绝对值的元素进行反转,以最小化对数组总和的负面影响。

4. 边界情况:

  • 如果数组中没有负数,所有操作只能对正数进行反转,那么我们应该确保尽量少反转大数,因为这会导致和下降。
  • 如果 k 已经用完,那么我们无需再做任何操作。

代码展示

def solution(nums: list, k: int) -> int:
    # 先将数组按绝对值大小排序,绝对值大的元素优先被操作
    nums.sort(key=abs, reverse=True)
    
    # 对数组进行操作
    for i in range(len(nums)):
        if k == 0:
            break
        # 如果当前元素是负数,且我们还有操作次数,进行反转
        if nums[i] < 0:
            nums[i] = -nums[i]
            k -= 1
    
    # 如果操作次数 k 剩余为奇数,选择最小的元素反转一次
    if k % 2 == 1:
        nums.sort()  # 重新排序,这时最小的元素在前
        nums[0] = -nums[0]  # 将最小元素反转一次
    
    # 返回数组的总和
    return sum(nums)

# 测试用例
if __name__ == '__main__':
    print(solution(nums=[-4, 2, 3], k=1) == 9)  # 预期输出:9
    print(solution(nums=[-3, -1, 0, 3], k=3) == 7)  # 预期输出:7
    print(solution(nums=[-2, -3, -1, 5, -4], k=2) == 9)  # 预期输出:9

时间复杂度分析

  • 排序:O(n log n),其中 n 是数组的大小。
  • 遍历数组:O(n),在最多遍历一遍数组时进行操作。
  • 总的时间复杂度为 O(n log n),其中 n 是数组的长度。