简体   繁体   中英

how to find 3 Numbers with Sum closest to a given number

I'm trying to write simple code for that problem. If I get an array and number I need to find the 3 numbers that their sum are close to the number that's given.

I've thought about first to pop out the last digit (the first number) then I'll have a new array without this digit. So now I look for the second number who needs to be less the sum target. so I take only the small numbers that it's smaller them the second=sum-first number (but I don't know how to choose it.

The last number will be third=sum-first-second

I tried to write code but it's not working and it's very basic

def f(s,target):
s=sorted(s)
print(s)
print(s[0])
closest=s[0]+s[1]+s[2]
m=s[:-1]
print(m)
for i in range(len(s)):
    for j in range(len(m)):
        if (closest<=target-m[0]) and s[-1] + m[j] == target:
    print (m[j])

n = m[:j] + nums[j+1:]
for z in range (len(z)):
    if (closest<target-n[z]) and s[-1]+ m[j]+n[z] == target:
    print (n[z])



 
s=[4,2,12,3,4,8,14]
target=20
f(s,target)

if you have idea what to change here. Please let me know Thank you

Here is my solution I tried to maximize the performance of the code to not repeat any combinations. Let me know if you have any questions. Good luck.

def find_3(s,target):

 to_not_rep=[] #This list will store all combinations without repetation
 close_to_0=abs(target - s[0]+s[1]+s[2]) #initile 
 There_is_one=False #False: don't have a combination equal to the target yet
 for s1,first_n in enumerate(s):
    for s2,second_n in enumerate(s):
        if (s1==s2) : continue #to not take the same index
        for s3,third_n in enumerate(s):
            if (s1==s3) or (s2==s3) : continue #to not take the same index
            val=sorted([first_n,second_n,third_n]) #sorting  
            if val in to_not_rep :continue #to not repeat the same combination with diffrent positions  
            to_not_rep.append(val)#adding all the combinations without repetation
            sum_=sum(val) #the sum of the three numbers
            # Good one
            if sum_==target:
                print(f"Found a possibility: {val[0]} + {val[1]} + {val[2]} = {target}")
                There_is_one = True 
            
            if There_is_one is False: #No need if we found combination equal to the target
                # close to the target
                # We know that (target - sum) should equal to 0 otherwise :
                # We are looking for the sum of closet combinations(in abs value) to 0
                pos_n=abs(target-sum_)
                if pos_n < close_to_0:
                    closet_one=f"The closet combination to the target is: {val[0]} + {val[1]} + {val[2]} = {sum_} almost {target} "
                    close_to_0=pos_n
 # Print the closet combination to the target in case we did not find a combination equal to the target 
 if There_is_one is False: print(closet_one) 

so we can test it:

s =[4,2,3,8,6,4,12,16,30,20,5]
target=20
find_3(s,target)
#Found a possibility: 4 + 4 + 12 = 20
#Found a possibility: 2 + 6 + 12 = 20
#Found a possibility: 3 + 5 + 12 = 20

another test:

s =[4,2,3,8,6,4,323,23,44]
find_3(s,target)
#The closet combination to the target is: 4 + 6 + 8 = 18 almost 20 

This is a simple solution that returns all possibilites. For your case it completed in 0.002019 secs

from itertools import combinations
import numpy as np
def f(s, target):
    dic = {}
    for tup in combinations(s, 3):
        try:
            dic[np.absolute(np.sum(tup) - target)].append(str(tup))
        except KeyError:
            dic[np.absolute(np.sum(tup) - target)] = [tup]
    print(dic[min(dic.keys())])

Use itertools.combinations to get all combinations of your numbers without replacement of a certain length (three in your case). Then take the three-tuple for which the absolute value of the difference of the sum and target is minimal. min can take a key argument to specify the ordering of the iterable passed to the function.

from typing import Sequence, Tuple

def closest_to(seq: Sequence[float], target: float, length: int = 3) -> Tuple[float]:
    from itertools import combinations

    combs = combinations(seq, length)
    diff = lambda x: abs(sum(x) - target)

    return min(combs, key=diff)

closest_to([4,2,12,3,4,8,14], 20) # (4, 2, 14)

This is not the fastest or most efficient way to do it, but it's conceptionally simple and short.

Something like this?

import math

num_find = 1448
lst_Results = []
i_Number = num_find

while i_Number > 0:
    num_Exp = math.floor(math.log(i_Number) / math.log(2))
    lst_Results.append(dict({num_Exp: int(math.pow(2, num_Exp))}))
    i_Number = i_Number - math.pow(2, num_Exp)

print(lst_Results)

In a sequence of numbers: for example 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, etc...

The sum of the previous numbers is never greater than the next. This gives us the possibility of combinations, for example: The number: 1448, there is no other combination than the sum of the previous numbers: 8 + 32 + 128 + 256 + 1024

Then you find the numbers whose sum is close to the number provided

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM