📜  门| GATE-CS-2016(Set 2)|第63章(1)

📅  最后修改于: 2023-12-03 15:28:44.758000             🧑  作者: Mango

GATE-CS-2016(Set 2) 第63道题

这道题是GATE-CS-2016(Set 2)中的第63道。它是一道典型的算法题,主要考察的是动态编程和贪心算法。题目要求:

给出一个数字的序列和一个目标数,找出数组中的一些数使它们的和正好等于目标数。你可以在序列中选择多个数字,在这里,你不需要考虑数字的顺序。例如,对于序列[1,3,5,7]和目标为8,找出数字1和7的索引是(0,3);找到数字3和5索引是(1,2)。

解题思路
动态编程

动态编程是一个常用的算法来解决求解最优解问题。来看一下这道题: 求和问题中的动态编程算法是非常直观的 -

我们定义一个 dp 数组,并初始化为 False。然后将 dp[0] 初始化为 True,因为总和为 0 元素总是存在的。

现在,我们遍历整个数组并更新 dp 数组。对于每个数字 arr[i],我们设置 dp[j] = True 对于任何可行的 j,该数字之前的子数组和为 j(包括 j)。

例如,假设我们正在处理 arr[2],并且之前已经有一个 dp 数组,如下所示:

dp[] = [0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

在处理 arr[2] 之后,dp 数组会变成 -

dp[] = [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

我们注意到,对于 j=0j=arr[i],除了 dp[0],所有的 dp[j] 元素都会被更新为 True。 这是因为对于任何 j>arr[i],只需添加 arr[i] 才能获得一个新的总和,而我们已经考虑了之前的元素。

我们需要做的就是迭代整个 dp 数组并返回 dp[target]

贪心算法

假设我们有一个包含正整数的数组和一个目标数 target

我们需要找到一个连续的子数组,其中元素的总和为 target 或者最接近 target,并返回这个和。

例如,假设输入数组为 [1, 2, 3, 4, 5],目标和为 7,那么选择子数组 [2, 3, 4],其和为 9`,最接近目标和。

贪心算法的基本思想是保持一个滑动窗口,在窗口中一直增加数字,直到总和超过 target。然后我们从窗口左侧移除数字,直到总和小于 target 为止。如果当前和等于目标和,则我们找到了一个解,返回这个和。否则,我们继续滑动窗口直到找到和最接近目标和的子数组。

代码实现
动态编程
def subsetsum(nums, target):
    n = len(nums)
    dp = [[False] * (target+1) for i in range(n+1)]

    for i in range(n+1):
        dp[i][0] = True

    for i in range(1, n+1):
        for j in range(1, target+1):
            if j < nums[i-1]:
                dp[i][j] = dp[i-1][j]
            else:
                dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i-1]]

    return dp[n][target]
贪心算法
def get_gap_sum(nums, target):
    left = right = cur_sum = 0
    gap = float("inf")
    sub_arr_sum = None
    
    while right < len(nums):
        cur_sum += nums[right]
        while left <= right and cur_sum > target:
            cur_sum -= nums[left]
            left += 1

        if abs(target - cur_sum) < gap:
            gap = abs(target - cur_sum)
            sub_arr_sum = cur_sum

        right += 1

    return sub_arr_sum
总结

动态编程和贪心算法是常用的求解优化问题的算法。对于不同的问题,我们可以选择不同的算法来解决。在本例中,动态编程算法可以找出是否存在一个子集和与目标相等,但是它不会找到最接近目标和的子集和。贪心算法能够快速找到与目标和最接近的子集和,但它并不能保证一定是最优的。