📜  根据给定条件,从整数对数组中最大化选定整数的总和(1)

📅  最后修改于: 2023-12-03 14:55:40.499000             🧑  作者: Mango

根据给定条件,从整数对数组中最大化选定整数的总和

问题描述

给定一个整数对数组 nums ,其中nums[i] = [a[i], b[i]] ,要求从中选取若干个整数,并使这些整数满足以下条件:

  • 选取的整数中,不能同时选取两个来自同一对 [a[i], b[i]] 中的整数
  • 选取的整数中,任意两个整数 [a[i1], b[i1]] 和 [a[i2], b[i2]] 之间必须满足 i1 != i2 且 a[i1] + b[i1] <= a[i2] 或 a[i2] + b[i2] <= a[i1] 的限制。

输出满足条件的整数对中,整数之和的最大值。

示例
示例1

输入:nums = [[3,4],[2,3],[1,2]] 输出:6 解释:选取 [1,2] 和 [3,4]。选取 [2,3] 会违反第二个限制条件。

示例2

输入:nums = [[1,3],[2,4],[3,6]] 输出:10 解释:选取 [1,3] 和 [3,6]。

解题思路

本题涉及到贪心算法和动态规划算法。

首先将给定的整数对数组按照 a[i] + b[i] 从小到大排序。

根据题目中的第一个限制条件,可以得到以下贪心策略:每次选取 a[i] + b[i] 最小的整数对中的较大值。

这是因为,如果选取了某个整数对的较小值,那么就不能再选取与之匹配的整数对中的较大值,这将导致可能出现不可选取较大值的情况,从而降低整数之和的最大值。

但是,直接按照以上贪心策略选取整数对可能不满足第二个限制条件。对此,需要运用动态规划算法,设计一个状态转移方程,来检验当前选定的整数对是否符合第二个限制条件。

具体来说,设 dp[i][0] 表示只选取前 i 个整数对,不选取第 i 个整数对时的最大整数之和;dp[i][1] 表示只选取前 i 个整数对,选取第 i 个整数对时的最大整数之和。则状态转移方程如下:

  • 当不选取第 i 个整数对时,dp[i][0] = max(dp[i-1][0], dp[i-1][1]);
  • 当选取第 i 个整数对时,则需要在前 i-1 个整数对中找到满足第二个限制条件的最后一个整数对 j,并满足 a[j] + b[j] <= a[i],这样才能选取第 i 个整数对。则 dp[i][1] = max(dp[j][0], dp[j][1]) + a[i]。

最终的解即为 max(dp[n][0], dp[n][1]),其中 n 为整数对数组的长度。

代码实现
def maxSum(nums: List[List[int]]) -> int:
    n = len(nums)
    nums.sort(key=lambda x: x[0] + x[1])
    dp = [[0,0] for _ in range(n+1)]
    for i in range(1, n+1):
        j = i - 1
        while j > 0 and nums[j-1][0] + nums[j-1][1] <= nums[i-1][0]:
            j -= 1
        dp[i][0] = max(dp[i-1][0], dp[i-1][1])
        if j > 0:
            dp[i][1] = max(dp[j][0], dp[j][1]) + nums[i-1][0]
    return max(dp[n][0], dp[n][1])

以上代码的时间复杂度为 $O(n^2)$,空间复杂度为 $O(n)$。可以根据具体场景进行优化,例如使用滚动数组减小空间复杂度,或者使用二分查找来寻找最后一个符合第二个限制条件的整数对。