人一我百,|

胖柚の工作室

园龄:2年1个月粉丝:2关注:15

2024-07-07 09:16阅读: 6评论: 0推荐: 0

相向双指针

167. 两数之和Ⅱ-输入有序数组

class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> ans;
int n = numbers.size();
int l = 0, r = n - 1;
while (l < r) {
if ((numbers[l] + numbers[r]) == target) {
ans.push_back(l+1), ans.push_back(r+1);
break;
} else if ((numbers[l] + numbers[r]) < target) {
l++;
} else r--;
}
return ans;
}
};

15.三数之和

本题可以看作两数之和的升级版,即固定一个数不动,看另外两个数之和是否等于这个数的相反数。时间复杂度为 O(n2). (枚举第一个数为 O(n),双指针为 O(n))。

class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());//先排序,方便尺取
vector<vector<int>> ans;
int n = nums.size();
for (int i = 0; i < n - 2; i++) {
int x = nums[i];
if (i && x == nums[i - 1]) continue;//跳过重复数字(当前nums[i]已经被使用过)
if (x + nums[i + 1] + nums[i + 2] > 0) break;//当x与其后的两个数之和大于0,说明这组无解(后面的数变大或x变大都不可能再等于0)
if (x + nums[n - 2] + nums[n - 1] < 0) continue;//如果x与最后面的两个数之和小于0,说明后面两个数变小也仍然小于0,只有增大x。
int l = i + 1, r = n - 1;
while (l < r) {
int sum = x + nums[l] + nums[r];
if (sum > 0) r--;
else if (sum < 0) l++;//尺取
else {
ans.push_back({x, nums[l], nums[r]});
l++;//当前的l和r所指向的数下回不能再使用。
while (l < r && nums[l] == nums[l - 1]) l++;
r--;
while (l < r && nums[r] == nums[r + 1]) r--;
}
}
}
return ans;
}
};

2824.统计和小于目标的下标对数目

class Solution {
public:
int countPairs(vector<int>& nums, int target) {
int n = nums.size();
int l = 0, r = n - 1, ans = 0;
sort(nums.begin(), nums.end());
while (l < r) {
int sum = nums[l] + nums[r];
if (sum >= target) {
r--;//nums[r]与下标i在[l, r-1]中的任何nums[i]相加都>=target
} else if (sum < target) {
ans += r - l;//nums[l]与下标i在[l+1, r]中的任何nums[i]相加都<target
l++;
}
}
return ans;
}
};

16.最接近的三数之和

class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size(), ans;
int MIN = 0x3f3f3f3f;
for (int i = 0; i < n - 2; i++) {
int x = nums[i];
if (i && x == nums[i - 1]) continue;
int s = x + nums[i + 1] + nums[i + 2];
if (s > target) {// 后面无论怎么选,选出的三个数的和不会比 s 还小
if (s - target < MIN) {
MIN = s - target;
ans = s;
}
break;
}
s = x + nums[n - 2] + nums[n - 1];
if (s < target) {
if (target - s < MIN) {
MIN = target - s;
ans = s;
}
continue;
}
int l = i + 1, r = n - 1;
while (l < r) {
s = x + nums[l] + nums[r];
if (s == target) {
return target;
} else if (s > target) {
if (s - target < MIN) {
MIN = s - target;
ans = s;
}
r--;
} else {
if (target - s < MIN) {
MIN = target - s;
ans = s;
}
l++;
}
}
}
return ans;
}
};

611.有效三角形的个数

错误解法:固定最小边

class Solution {
public:
int triangleNumber(vector<int>& nums) {
int n = nums.size(), ans = 0;
sort(nums.begin(), nums.end());
for (int i = 0; i < n - 2; i++) {
int x = nums[i];
int l = i + 1, r = n - 1;
while (l < r) {
if (x + nums[l] > nums[r]) {
ans += r - l;
l++;
} else {
r--;
}
}
}
return ans;
}
};

这里错误的原因主要是,在固定最小边 a 时,我们的目标是使得 a + b > c,但现在 a 在不等号左边,也就是当 a + b c 时,不知道是 b 较小造成的还是 c 较大造成的。固定最大边就能保证一定是左边太小造成的。

正确解法:固定最大边

class Solution {
public:
int triangleNumber(vector<int>& nums) {
int n = nums.size(), ans = 0;
sort(nums.begin(), nums.end());
for (int k = 2; k < n; k++) {
int l = 0, r = k - 1;
while (l < r) {
int s = nums[l] + nums[r];
if (s > nums[k]) {
// nums[l]+nums[r] > c 同时意味着:
// nums[l+1]+nums[r] > c
// nums[l+2]+nums[r] > c
// ...
// nums[r-1]+nums[r] > c
// 从 l 到 r-1 一共 r-l 个
ans += r - l;
r--;
} else {
// nums[l]+nums[r] <= c 同时意味着
// nums[l]+nums[r-1] <= c
// ...
// nums[l]+nums[l+1] <= c
// 所以在后续的内层循环中,nums[l] 不可能作为三角形的边长,没有用了
l++;
}
}
}
return ans;
}
};

18.四数之和

class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> ans;
for (int i = 0; i < n - 3; i++) {
long long x = nums[i];
if (i && x == nums[i - 1]) continue;
if (x + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
if (x + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) continue;
for (int j = i + 1; j < n - 2; j++) {
int y = nums[j];
if (j > i + 1 && y == nums[j - 1]) continue;
if (x + y + nums[j + 1] + nums[j + 2] > target) break;
if (x + y + nums[n - 2] + nums[n - 1] < target) continue;
int l = j + 1, r = n - 1;
while (l < r) {
long long s = x + y + nums[l] + nums[r];
if (s > target) r--;
else if (s < target) l++;
else {
ans.push_back({(int)x, (int)y, nums[l], nums[r]});
l++;
while (l < n && nums[l] == nums[l - 1]) l++;
r--;
while (r > j && nums[r] == nums[r + 1]) r--;
}
}
}
}
return ans;
}
};

11.盛最多水的容器

哪边的木板短,就把哪边的木板去掉。(在中间的木板比短木板长或比短木板短都无法更新 ans

class Solution {
public:
int maxArea(vector<int>& h) {
int n = h.size();
int ans = 0;
int l = 0, r = n - 1;
while (l < r) {
int x = r - l, y = min(h[l], h[r]);
int s = x * y;
ans = max(ans, s);
if (h[l] <= h[r]) {
l++;
} else {
r--;
}
}
return ans;
}
};

42. 接雨水

class Solution {
public:
int trap(vector<int>& h) {
int n = h.size();
int pre = 0, suf = 0, ans = 0;
int l = 0, r = n - 1;
while (l < r) {
pre = max(pre, h[l]);
suf = max(suf, h[r]);
if (pre <= suf) {
ans += pre - h[l];
l++;
} else {
ans += suf - h[r];
r--;
}
}
return ans;
}
};

本文作者:pangyou3s

本文链接:https://www.cnblogs.com/pangyou3s/p/18288207

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   胖柚の工作室  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起