two-sum变种系列

933 阅读3分钟

本文是two-sum系列的变种,主要讨论两道由改造而来的题目。

two_sum

找出无序数组中和为target的所有元素组合

给定一个无序数组,找出可能的相加之和为target的两个元素,返回它们的索引。 输入:

Example 1:

Given nums = [1,2,2,8,8,9], target = 10
Because Because nums[0] + nums[5] = 2 + 7 = 10,
nums[1] + nums[4] = 2 + 8 = 10,
nums[1] + nums[3] = 2 + 87 = 10,
nums[2] + nums[4] = 2 + 8 = 10,
nums[2] + nums[3] = 2 + 8 = 10
return [[0, 5],[1,4],[1,3],[2,4],[2,3]].

Example 2:

Given nums = [7,4,4,4,1], target = 8
Because Because nums[0] + nums[4] = 7 + 1 = 8,
nums[1] + nums[2] = 4 + 4 = 8,
nums[1] + nums[3] = 4 + 4 = 8,
nums[2] + nums[3] = 4 + 4 = 8,
return [[1,2],[1,3],[2,3],[0,4]].

解法1:使用哈希表

用一个哈希表来记录元素arr[i]在哪些位置出现过。 依次遍历每个元素,在遍历第i个元素时,检查target-arr[i]是否存在于map中,如果有,说明,在0-i-1位置中存在某些位置上的元素等于target - arr[i],将位置i与这些位置组合后加入到结果集res。最后,将元素arr[i]及其位置i记录到map中。

vector<vector<int>> findTargetInUnsortedArray(vector<int> &arr, int target) {
    if (arr.size() < 2) {
        return {};
    }
    vector<vector<int>> res;
    map<int, vector<int>> pos;
    for (int i = 0; i < arr.size(); ++i) {
        int diff = target - arr[i];
        if (pos.find(diff) != pos.end()) {
            vector<int> tmp = pos[diff];
            for (int j = 0; j < tmp.size(); ++j) {
                res.push_back({tmp[j], i});
            }
        }
        pos[arr[i]].push_back(i);
    }
    return res;
}

时间复杂度:O(n),空间复杂度为:O(n)

有序数组中和为target的组合

给定一个有序数组,找出可能的相加之和为target的两个元素,返回它们的索引。 输入:

Example 1:

Given nums = [1,2,2,8,8,9], target = 10
Because Because nums[0] + nums[5] = 2 + 7 = 10,
nums[1] + nums[4] = 2 + 8 = 10,
nums[1] + nums[3] = 2 + 87 = 10,
nums[2] + nums[4] = 2 + 8 = 10,
nums[2] + nums[3] = 2 + 8 = 10
return [[0, 5],[1,4],[1,3],[2,4],[2,3]].

解法1:基于二分查找

依次遍历数组中的每个元素,在第i个位置处,

vector<vector<int>> findTargetInSortedArray(vector<int> &arr, int target) {
    if (arr.size() < 2) {
        return {};
    }
    vector<vector<int>> res;
    for (int i = 0; i < arr.size(); ++i) {
        int diff = target - arr[i];
        int index = findFirstOfTarget(arr, i + 1, arr.size() - 1, diff);
        
        while (index < arr.size() && arr[index] == diff) {
            res.push_back({i, index});
            ++index;
        }
    }
    return res;
}

时间复杂度为:O(nlogn),空间复杂度为:O(1)

解法2:使用哈希表

这里与无序数组的区别在于,在无序数组中,记录的是同一元素出现的每个位置。 如在下面的测试用例中:

Given nums = [7, 3, 2, 7, 8, 7, 9], target = 10

当遍历到最后一个元素9时,对于元素7,需要记录它在数组中的哪些位置出现过,即map的形式如下:

{7: [0, 3, 5]}

而对于有序数组:

Given nums = [2, 3, 7, 7, 7, 8, 9], target = 10

map的形式如下:

{7 :[2,4]}

只记录元素7出现的初始位置和结束位置即可。