[leetcode]求和类问题

Two sum i

Given an array of integers, return indices of the two numbers such that they add up to a specific target. 
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

Two sum系列算是leetcode经典题型了,哈希表的经典使用。 O(N)

vector<int> twoSum(vector<int>& nums, int target) 
{
    unordered_map<int, int> m;
    for (int i = 0; i < nums.size(); ++i)
        if (m.count(nums[i]))
            return vector<int>({ m.find(nums[i])->second, i });
        else
            m[target - nums[i]] = i;
    return vector<int>();
}

Two Sum ii

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number. 
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution and you may not use the same element twice.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

虽然这题的tag里有二分法,但貌似还没有 O(log(N)) 的解法。这题思路是使用双指针,首尾相加, O(N)

vector<int> twoSum(vector<int>& numbers, int target)
{
    int left = 0, right = numbers.size() - 1, sum;
    while (left < right)
    {
        sum = numbers[left] + numbers[right];
        if (sum == target)
            return vector<int>({ left + 1, right + 1 });
        else if (sum > target)
            --right;
        else
            ++left;
    }
    return vector<int>({ -1, -1 });
}

Two Sum iii

Design and implement a TwoSum class. It should support the following operations:add and find. 
add - Add the number to an internal data structure.
find - Find if there exists any pair of numbers which sum is equal to the value.
For example,
add(1); add(3); add(5);
find(4) -> true
find(7) -> false

其实跟Tow Sum i差不多的思路,只不过这个题目中有特殊情况:一个数字可能出现多次。
add O(1) , find O(N)

class TwoSum 
{
    unordered_map<int, int> map;
public:
    void add(int number) 
    {
        map[number]++;
    }
    bool find(int value) 
    {
        for (auto &p : map)
        {
            int i = p.first;
            int j = value - i;
            if ((i == j && p.second > 1) || (i != j && map.count(j)))
                return true;
        }
        return false;
    }
};

3Sum

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. 
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

The same as find an element a in S that existing two elements b and c that b + c = - a. First sort the array, then for each elements nums[i], find if there are two elements in range [i + 1, i + 2,…, n - 1] that nums[j] + nums[k] = - nums[i]. So this problem could reduce to Two Sum ii.
Complexity: O(N2) .

vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> ret;
    int N = nums.size();
    for (int i = 0; i < N - 2; ++i)
    {
        // skip duplicates
        if (i > 0 && nums[i] == nums[i - 1])
            continue;
        int sum = -nums[i];

        int left = i + 1, right = nums.size() - 1;
        while (left < right)
        {
            int target = nums[left] + nums[right];
            if (target < sum)
                ++left;
            else if (target > sum)
                --right;
            else
            {
                ret.push_back(vector<int>({ nums[i], nums[left], nums[right] }));
                // skip duplicates
                for (left = left + 1; left < right && nums[left] == nums[left - 1]; ++left);
                for (right = right - 1; left < right && nums[right] == nums[right + 1]; --right);
            }
        }
    }
    return ret;
}

3Sum-closest

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).

Same as 3sum, just keep record of every minimum gap. O(N2)

int threeSumClosest(vector<int>& nums, int target)
{
    int gap = INT_MAX;
    int ret;
    sort(nums.begin(), nums.end());
    int N = nums.size();
    for (int i = 0; i < N - 2; ++i)
    {
        if (i > 0 && nums[i] == nums[i - 1])
            continue;
        int left = i + 1, right = nums.size() - 1;
        while (left < right)
        {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum == target)
                return target;
            else if (sum < target)
                ++left;
            else
                --right;
            if (abs(target - sum) < gap)
            {
                gap = abs(target - sum);
                ret = sum;
            }
        }
    }
    return ret;
}

4sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note: The solution set must not contain duplicate quadruplets.
For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

This problem could be reduced to 3sum. Just add an extra loop for the extra variable. O(N3)

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> ret;
    int n = nums.size();
    for (int i = 0; i < n - 3; ++i)
    {
        if (i > 0 && nums[i] == nums[i - 1])
            continue;
        for (int j = i + 1; j < n - 2; ++j)
        {
            if (j > i + 1 && nums[j] == nums[j - 1])
                continue;
            int t1 = target - nums[i] - nums[j];
            // if the smallest two number's sum is still larger, just try next i
            if (nums[j + 1] + nums[j + 2] > t1)
                break;
            // if the largest two number's sum is still smaller, just try next j.
            if (nums[n - 1] + nums[n - 2] < t1)
                continue;
            int left = j + 1, right = nums.size() - 1;
            while (left < right)
            {
                int sum = nums[left] + nums[right];
                if (sum == t1)
                {
                    ret.push_back(vector<int>({ nums[i], nums[j], nums[left], nums[right] }));
                    // skip the duplicates
                    for (left = left + 1; left < right && nums[left] == nums[left - 1]; ++left);
                    for (right = right - 1; left < right && nums[right] == nums[right + 1]; --right);
                }
                else if (sum < t1)
                    ++left;
                else
                    --right;
            }
        }
    }
    return ret;
}

The trimming here is important to reduce the running time. Comments are added.

4Sum II

Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0

Idea: use a hashmap to store all combinations of Ai+Bj , then for each combination of sum=Ck+Dh , find if sum exists in the previous built hash-table. O(N2)

int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) 
{
    int N = A.size();
    unordered_map<int, int> sumMap;
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            ++sumMap[A[i] + B[j]];
    int res = 0;
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < N; ++j)
            if (sumMap.count(0 - C[i] - D[j]))
                res += sumMap[0 - C[i] - D[j]];
    return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值