找到三个整数,其总和最接近给定数字N.

时间:2014-09-21 19:44:35

标签: python arrays algorithm subset

阅读Finding three elements in an array whose sum is closest to a given number后,这是我尝试实现此类算法

def findThree(seq, goal):

    # initialize the differences 
    goalDifference = float("inf")
    dl = -1
    dr = -1
    dx = -1

    for x in range(len(seq)-1):

        left = x+1
        right = len(seq)-1


        while (left < right):

            # if the absolute value of the previous set and the goal is less than the current goalDifference,
            # keep track of the new set
            if(abs(goal - (seq[left] + seq[right] + seq[x])) < goalDifference):
                dl = left
                dr = right
                dx = x

            tmp = seq[left] + seq[right] + seq[x]

            if tmp > goal:
                right -= 1
            elif tmp < goal:
                left += 1
            else:
                return [seq[left],seq[right],seq[x]]

    # if no match is found, return the closest set
    return [seq[dl],seq[dr], seq[dx]]

该算法非常适合找到精确的解决方案,给定

arr = [89, 120, 140, 179, 199, 259, 259, 259, 320, 320]

findThree(arr, 349) // want to get [120, 140, 89]
>> [120, 140 89] // success

findThree(arr, 439) // want to get [140, 179, 120]
>> [140, 179,120] // success

然而,当我想看它是否会返回最近的时候,它会返回

findThree(arr, 350) // only 1 more than 349, should return [120, 140, 89]
>> [320, 320, 259] // fail

findThree(arr, 440) // only 1 more than 439, should return [140, 179, 120]
>> [320, 320, 259] // fail

似乎当我希望它返回“cloest”元素时,它总是返回[320,320,259]。我一直在看代码几个小时,但仍然无法弄清楚是什么问题。

3 个答案:

答案 0 :(得分:4)

我很快查看了你的代码,主要的问题是“目标差异”从未改变过。

你需要随意挤出“净胜球”,否则所有组合都在“球门差异”范围内,显然你最终会将最后一组作为答案。

答案 1 :(得分:0)

您可以执行以下操作:

def find3(tgt, arr):
    lowest=[float('inf')]
    for i in range(0,len(arr)-2):
        j=i+1
        k=len(arr)-1
        while k>=j:
            t=tuple(arr[x] for x in (i, j, k) )
            sum_t=sum(t)
            if sum_t==tgt:
                return t
            elif sum_t<sum(lowest):
                lowest=t     
            if sum_t>0:
                k-=1
            else:
                j+=1                    

    return lowest

适用于您描述的所有案例。

答案 2 :(得分:0)

实际上,这里的问题是你没有跟踪最接近的数字组合。根据当前算法,您的代码会检查组合,直到left = right-1x=left-1 (since left = x+1);。在循环执行结束时,如果未实现正确的组合,您将始终拥有x=259left=320right=320。这就是为什么当调用[320, 320, 259]findThree(arr, 350)时,它返回最后一次迭代的值总是findThree(arr, 440)。 一个解决方案可能是采用三个变量close1 close2close3并在for循环开始之前将它们初始化为0;并且在for循环之后在if语句之后添加以下内容:

if(abs(goal - (seq[left] + seq[right] + seq[x])) < abs(goal - (close1 + close2 + close3)) ):
close1 = seq[left]
close2 = seq[right]
close3 = seq[x]

上述语句将检查最接近上一组和当前数组的leftrightx元素,并更改close1,{{1如果当前组合比close2close2left的上一条记录更接近,则{}}和right到当前的左,右和x集合,xclose1存储在{{}分别为1}},close2close3。否则close1close2close3不得更改。 并在代码的末尾

#if no match is found,return the closest set
return [close1 ,close2, close3]