-
题目:剑指Offer57.和为s的两个数字
一个有序数组nums,返回任意一对和为target的数字;
若存在多对,则取二者乘积最小的一组; -
思路:
1.双指针:O(n),O(1)
数组本身有序,这是可以使用双指针的原因;
之所以两侧遇到的的第一对就是乘积最小的,等价于一根绳子折成的四边形中,正方形面积最大
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
if (n < 2) return {};
for (int i = 0, j = n - 1; i < j; ) {
int sum = nums[i] + nums[j];
if (sum > target) --j;
else if (sum < target) ++i;
else return {nums[i], nums[j]};
}
return {};
}
2.若果本题要求随便找到一对组合,是可以的;但要求乘积最小,因为这种方式是边遍历边存,因此只有遇到某对组合的右边那个数才能查到,若在这之前提前遇到了另一对数的右边那个数,返回的就不是预期的最两侧的那对数了;例如数组为1~20,target=21,则目标为[ 1,20 ],但在这之前提前遇到了[ 10,11 ]
哈希表:时间O(n):遍历一次,最坏情况下目标数在数组末尾,就需要把n-1个数都insert进哈希表,insert操作是O(1),空间O(n):最坏需要存n-1个数
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_set<int> us;
for (auto x : nums) {
if (us.find(target - x) != us.end()) return {target - x, x};
else us.insert(x);
}
return {};
}
};
- 总结:
对于O(n ^ 2)的,通常可以使用哈希表或双指针(双指针需要有序)将其优化为O(n);