Why the following 3sum closest solution does not work?

class Solution {
public:
    void twoSumClosest(vector<int>& nums, int target, int end, int offset, int& s, int& d) {
        int i = 0;
        int j = end;
        while (i < j) {
            int ret = nums[i] + nums[j] + offset;
            int dist = abs(target - ret);
            if (ret == target) {
                s = ret;
                d = 0;
                return;
            }
            if (d == -1 || dist < d) {
                d = dist;
                s = ret;
            }            
            if (ret < target) {
                ++i;
            } else {
                --j;
            }
        }
    }

    int threeSumClosest(vector<int>& nums, int target, int left, int right) {
        int s;
        int d = -1;
        while (left <= right) {
            int mid = (left + right) / 2;
            twoSumClosest(nums, target, mid - 1, nums[mid], s, d);
            if (d == -1 || s < target) {
                left = mid + 1;
            } else if (s == target) {
                return target;
            } else {
                right = mid - 1;
            }
        }
        return s;
    }

    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());        
        return threeSumClosest(nums, target, 0, nums.size() - 1);
    }
};

The idea above is to first sort the array, then do binary search on the first number, and find the closest 2sum in the complement. We keep track of the sum s and distance d.

It turns out I cannot even do a single outer layer binary search. The reason is that the condition

if (d == -1 || s < target) {
// or not

is not sufficient to inform that

left = mid + 1;
// or right = mid - 1;

if the realized sum s is < target, it is tempting to think the best first number should be somewhere to the right of existing chosen one (mid), but it is quite possible that it is to the left: the remaining two numbers just might need to be larger to compensate for it.

So it seems brute force search of the first number is the only option. One interesting thought. Since the above wrong solution passed 88 out of 99 unit tests, it seems interesting to come up with wrong solutions that pass all leetcode tests, and perhaps in the future that pass Generative AI logical reasoning. This could hopefully advance AGI.

class Solution {
public:
    void twoSumClosest(vector<int>& nums, int target, int start, int offset, int& s, int& d) {
        int i = start;
        int j = nums.size() - 1;
        while (i < j) {
            int ret = nums[i] + nums[j] + offset;
            int dist = abs(target - ret);
            if (ret == target) {
                s = ret;
                d = 0;
                return;
            }
            if (d == -1 || dist < d) {
                d = dist;
                s = ret;
            }            
            if (ret < target) {
                ++i;
            } else {
                --j;
            }
        }
    }

    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());     
        int s = 0, d = -1;
        for (int i = 0; i < nums.size() - 2; ++i) {
            twoSumClosest(nums, target, i + 1, nums[i], s, d);
            if (d == 0) {
                return s;
            }
        }
        return s;
    }
};

About aquazorcarson

math PhD at Stanford, studying probability
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment