Given an array of integers, 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. Input: numbers={2, 7, 11, 15}, target=9 Output: index1=1, index2=2
这个题其实就是对vector中每个数,查找相应的target - vector.at(i)
复杂度优化就只能从查找方法入手了:整体复杂度就是O(n) * t (t为以下各种方法的复杂度)
1.最普通的遍历查找 O(n) 好像超时了 哈哈
2.二分查找,O(lgn) 可惜不是有序的,用不上
3. map:C++ map采用红黑树实现,查找时间复杂度为O(lgn)
4. hash:map和hash其实都是一种映射关系,只是当key有个区间范围时可以直接O(1)精准制导,随机存取的。c++11提供了unordered_map 实际上就是hash
class Solution { public: vector<int> twoSum(vector<int> &numbers, int target) { vector<int> res; unordered_map<int, int> table; for (int i = 0; i < numbers.size(); ++i) { table.insert({numbers.at(i), i}); } for (int i = 0; i < numbers.size(); ++i) { auto it = table.find(target - numbers.at(i)); if (it != table.end() && it->second != i) { res.push_back(min(it->second, i) + 1); res.push_back(max(it->second, i) + 1); break; } } return res; } };
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: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) 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)
解题分析:
方法一:直接三层循环暴力求解,T(n) = O(n^3) 会超时
方法二: 首先将数组排序,然后顺序遍历每一个vec.at(i), 求解 vec.at(low) + vec.at(high) = target = -vec.at(i) 的数对
因为数组已经有序了,我们可以让下标low指向 i+1, high指向 size() - 1, 然后相加
如果 相加和 大于 target,high--
如果 相加和 小于 target,low++
T(n) = O(n^2)
方法三: 外层顺序遍历每一个vec.at(i),内层顺序遍历每一个vec.at(j),然后查找 target = -(vec.at(i) + vec.at(j))
此时查找我们使用 哈希表 来进行 O(1)查找
T(n) = O(n^2)
1 class Solution { 2 public: 3 vector<vector<int> > threeSum(vector<int> &num) { 4 vector<vector<int>> emptyVec; 5 if (num.size() < 3) return emptyVec; 6 sort(num.begin(), num.end()); 7 vector<vector<int>> res; 8 9 int icurrentValue = num.at(0); 10 for (int i = 0; i < num.size() - 2; ++i) { 11 if (i && icurrentValue == num.at(i)) { 12 continue; 13 } 14 int low = i + 1; 15 int high = num.size() - 1; 16 int target = -1 * num.at(i); 17 while (low < high) { 18 int total = num.at(low) + num.at(high); 19 if (total == target) { 20 res.push_back({num.at(i), num.at(low), num.at(high)}); 21 ++low; 22 --high; 23 } else if (total < target) { 24 ++low; 25 } else { 26 --high; 27 } 28 icurrentValue = num.at(i); 29 } 30 } 31 32 33 auto iter = unique(res.begin(), res.end()); 34 res.resize(distance(res.begin(), iter)); 35 return res; 36 } 37 };
此题最需要注意的是:结果需要去重,即不能存在重复的数对
这时我们可以采用两种方法:
1. 使用 set<vector<int>> 来保证唯一性,但是 set容器的插入操作底层是利用二叉树实现的,插入操作T(n) = O(log n) (n为结果数,n可能非常大)
2. 使用 vector<vector<int>>,然后最后的时候 使用 std::unique
但是使用 std::unique的前提是容易必须有序
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).
解题分析:
本题需要求最接近解,我们只需要保存当前解和目标的距离,如果新的解更接近,则更新解
class Solution { public: int threeSumClosest(vector<int> &num, int target) { int result = 0; sort(num.begin(), num.end()); int minDiff = INT_MAX; for (int i = 0; i < num.size() - 2; ++i) { int target2 = target - num.at(i); int twoSum = twoSumClosest(num, i + 1, target2); if (abs(twoSum - target2) < minDiff) { minDiff = abs(twoSum - target2); result = num.at(i) + twoSum; if (result == target) { return result; } } } return result; } int twoSumClosest(vector<int>& num, int start, int target) { int low = start; int high = num.size() - 1; int minDiff = INT_MAX; int result = 0; while (low < high) { int sum = num.at(low) + num.at(high); if (sum < target) { if (target - sum < minDiff) { minDiff = target - sum; // 确保绝对值差最小,即最接近 result = sum; } ++low; } else if (sum > target) { if (sum - target < minDiff) { minDiff = sum - target; // 确保绝对值差最小,即最接近 result = sum; } --high; } else { return target; } } return result; } };
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: Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d) 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)
解题分析:
这题同3sum一样,首先num.at(i)外循环, num.at(j)内循环,最后 用两个游标寻找 sum = target - nun.at(i) - num.at(j)的解对
注意题目需要去重
class Solution { public: vector<vector<int> > fourSum(vector<int> &num, int target) { vector<vector<int>> res; if (num.size() < 3) return res; sort(num.begin(), num.end()); for (int i = 0; i < num.size() - 3; ++i) { if (i > 0 && num.at(i) == num.at(i-1)) continue; // 防止第一个元素重复 for (int j = i + 1; j < num.size() - 2; ++j) { if (j > i + 1 && num.at(j) == num.at(j-1)) continue; // 防止第二个元素重复 int target2 = target - num.at(i) - num.at(j); int first = j + 1; int last = num.size() - 1; while (first < last) { int sum = num.at(first) + num.at(last); if (sum < target2) { ++first; } else if (sum > target2) { --last; } else { res.push_back(vector<int>{num.at(i), num.at(j), num.at(first), num.at(last)}); ++first; --last; } } } } res.erase(unique(res.begin(), res.end()), res.end()); return res; } };