剑指 Offer 57. 和为s的两个数字
剑指 Offer 57. 和为s的两个数字
1.暴力循环
运行时间超限。复杂度是O(n^2).
点击查看代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans(2);
const int size = nums.size();
for(int p = 0; p < size - 1; p++){
if(nums[p] + nums[p+1] > target) break;
for(int q = p + 1; q < size; q++){
if(nums[p] + nums[q] > target) break;
if(nums[p] + nums[q] == target){
ans[0] = nums[p];
ans[1] = nums[q];
return ans;
}
}
}
return ans;
}
};
2.在暴力的基础上加一点小改进(二分)
复杂度O(nlogn)
执行用时: 208 ms
内存消耗: 98.3 MB
点击查看代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans(2);
const int size = nums.size();
for(int p = 0; p < size - 1; p++){
int left = p + 1, right = size - 1;
int mid = left + (right - left) / 2;
while(left <= right){
if(nums[mid] == target - nums[p]){
ans[0] = nums[p];
ans[1] = nums[mid];
return ans;
}
if(nums[mid] < target - nums[p])
left = mid + 1;
else
right = mid - 1;
mid = left + (right - left) / 2;
}
}
return ans;
}
};
3.双指针移动法,复杂度O(n)
看了题解,发现居然有这么妙的方法!
一个升序数组,要找两个数相加得到一个目标数,我们可以从两端开始寻找,设有两个指针p和q,分别指向数组的首端(最小值)和尾端(最大值)。
计算num[p]+num[q](第一个被计算的值是num[0]和num[size - 1],如果这个值小于目标值,那么移动左边的指针(c语言的操作是p++),这样我们舍弃了num[0]+num[size - 2], num[0]+num[size - 3], ... ,num[0]+num[1]这些不可能的解。为什么这些值不可能?num[size - 1] 比所有数组中的元素都要大,它与num[0]相加都小于target,说明在他左边的数与num[0]相加更不可能等于target。理解了这一点,就知道这个双指针算法是如何运行的了。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans(2);
const int size = nums.size();
int p = 0, q = size - 1;
while(p < q){
if(nums[p] + nums[q] == target){
ans[0] = nums[p];
ans[1] = nums[q];
return ans;
}
if(nums[p] + nums[q] < target) p++;
else q--;
}
return ans;
}
};

浙公网安备 33010602011771号