简体   繁体   中英

Find three Numbers with Sum closest to a given number

I am trying to solve a problem where,

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

 For example, given array S = {-1 2 1 -4}, and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). 

My solution is: take a number out (number_1) from the array, set the target to target - that number and find two other numbers which are closest to the new target. This way: number_1 + number_2 + number_3 will be closest as number_2 + number_3 will be closest to target - number_1.

I tried my solution at https://leetcode.com/problems/3sum-closest/description/ .

My solution is:

def threeSumClosest(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    closest_sum = nums[0] + nums[1] + nums[2]

    for i in range(len(nums)):

        # Create temp array excluding a number

        if i!=len(nums)-1:
            temp = nums[:i] + nums[i+1:]

        else:
            temp = nums[:len(nums)-1]


        # Sort the temp array and set new target to target - the excluded number

        temp = sorted(temp)            
        l, r = 0, len(temp) -1 
        t = target - nums[i]

        while(l<r):

            if temp[l] + temp[r] == t:
                return target

            elif temp[l] + temp[r] > t:

                if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
                    closest_sum = temp[l] + temp[r] + nums[i]

                r = r - 1

            else:

                if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
                    closest_sum = temp[l] + temp[r] + nums[i]

                l = l + 1


        return closest_sum

It passes 80 test cases out of 125, so the solution logic looks fine enough for me.

It fails for:

Input:
[0,2,1,-3]
1
Output:
3
Expected:
0

Can't understand why it fails and how to make my logic consistent.

Thanks for your help.

You have couple of mistakes the first one is silly, you have an extra indentation in return closest and the second one is not checking updating closest in the 3rd if statement. This code got accepted:

class Solution(object):
def threeSumClosest(self, nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    closest = nums[0] + nums[1] + nums[2]

    #if len(nums)==3:
    #    return closest

    for i in range(len(nums)):
        if i!=len(nums)-1:
            temp = nums[:i] + nums[i+1:]
        else:
            temp = nums[:len(nums)-1]

        temp = sorted(temp)

        l, r = 0, len(temp) -1 
        t = target - nums[i]

        while(l < r):
            if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest - target):
                    closest = temp[l] + temp[r] + nums[i]

            if temp[l] + temp[r] == t:

                return target
            elif temp[l] + temp[r] > t:
                r = r - 1
            else:
                l = l + 1

    return closest

And this is an accepted C++ solution with O(n^2) running time:

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int ans = nums[0] + nums[1] + nums[2];
        for(int i = 0; i < nums.size() - 2; i++) {
            int l = i + 1, r = nums.size() - 1;

            while (l < r) {
                if(abs(nums[i] + nums[l] + nums[r] - target) < abs(target - ans)) {
                    ans = nums[i] + nums[l] + nums[r];
                }
                if(nums[r] + nums[l] > target - nums[i]) r = r - 1;
                else l = l + 1;
            }
        }
        return ans;
    }
};

As we worked out in the comments the last return statment was erroneously inside the for loop cutting it short after the first iteration. Also, closest should be updated in both branches where we overshoot or undershoot the target.

I think an obvious improvement of your algorithm would be to sort first. Removing individual elements doesn't destroy order, so you'd need to sort only once. That would get you from O(n^2 log n) to O(n^2).

You can find all combinations of values in the list, and then find the listing whose sum is closest to the target:

import itertools
s = [{'vals':[-1, 2, 1, -4], 'target':1}, {'vals':[0,2,1,-3],'target':1}]
final_result = {tuple(a['vals']):sum(min(itertools.combinations(a['vals'], 3), key=lambda x:abs(a['target']-sum(x)))) for a in s}

Output:

{(-1, 2, 1, -4): 2, (0, 2, 1, -3): 0}

My solution works for this input:

[0,2,1,-3] 1

Your closest sum variable is incorrect. See my variable named "gap"

class Solution:
def threeSumClosest(self, nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    sorted_nums = sorted(nums)
    gap = sorted_nums[len(nums)-1] * 10000
    solution = 0

    for pointer_1 in range(len(sorted_nums)):
        pointer_2 = pointer_1 + 1
        pointer_3 = len(sorted_nums) - 1
        while(pointer_2 < pointer_3):
            gap_n = abs((sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3]) - target)
            add = (sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3])
            if (gap_n < gap):
                solution = add
                gap = gap_n
            elif (target > add):
                pointer_2 = pointer_2 + 1
            else:
                pointer_3 = pointer_3 - 1
    return solution

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