-
两数之和 II - 输入有序数组 https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/solution/san-shu-zhi-he-bu-hui-xie-xiang-xiang-sh-6wbq/
-
三数之和 https://leetcode.cn/problems/3sum/solution/shuang-zhi-zhen-xiang-bu-ming-bai-yi-ge-pno55/
课后作业: 2824. 统计和小于目标的下标对数目 https://leetcode.cn/problems/count-pairs-whose-sum-is-less-than-target/
167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)
关键词:有序 双向缩短长度
cpp
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
//双指针 双向缩短长度
int n=numbers.size();
int i=0;int j=n-1;
while(i!=j){
if(numbers[i]+numbers[j]==target){
return {i+1,j+1};
}
if(numbers[i]+numbers[j]>target){
j--;
}
else i++;
}
return {-1,-1};
}
};
重难点去重
cpp
// 去重:跳过重复的nums[k](避免重复三元组)
if (k < n - 1 && nums[k] == nums[k + 1]) continue;//跳过使用continue
//要保证k合法且重复
cpp
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int n = nums.size();
// 边界处理:长度不足3直接返回空
if (n < 3) return ans;
// 排序
sort(nums.begin(), nums.end());
// 枚举第三个元素 nums[k],转化为两数之和(nums[i]+nums[j] = -nums[k])
for (int k = n - 1; k >= 2; --k) { // 修正边界:k >= 2
// 去重:跳过重复的nums[k](避免重复三元组)
if (k < n - 1 && nums[k] == nums[k + 1]) continue;//跳过使用continue
int target = -nums[k]; // 两数之和的目标值
int i = 0, j = k - 1; // 双指针:i从头部,j从k-1开始
while (i < j) {
int sum = nums[i] + nums[j];
if (sum == target) {
// 找到有效三元组,加入结果
ans.push_back({nums[i], nums[j], nums[k]});
// 对i去重:循环跳过所有相同的nums[i]
while (i < j && nums[i] == nums[i + 1]) ++i;
// 对j去重:循环跳过所有相同的nums[j]
while (i < j && nums[j] == nums[j - 1]) --j;
// 移动指针找下一组可能的解 (一趟可能好几组解)
++i;
--j;
} else if (sum > target) { // 要写else if 前面没有return
// 和太大,j左移减小和
--j;
} else {
// 和太小,i右移增大和
++i;
}
}
}
return ans;
}
};
2824. 统计和小于目标的下标对数目 - 力扣(LeetCode)
跟两数之和很像。
核心思想:x<y<z
x+z<a ===>x+y定<a
cpp
class Solution {
public:
int countPairs(vector<int>& nums, int target) {
//0 <= i < j < n 且 nums[i] + nums[j] < target 的下标对 (i, j) 的数目。
int ans=0;
sort(nums.begin(),nums.end());
int n=nums.size();
int i=0;int j=n-1;
while(i<j){
int sum=nums[i]+nums[j];
if(sum>=target){
j--;
}
else{
ans+=(j-i);
i++;
}
}
return ans;
}
};
2824. 统计和小于目标的下标对数目 - 力扣(LeetCode)
cpp
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int n = nums.size();
sort(nums.begin(), nums.end());
int ans = 0;
int min_dis = INT_MAX;
for (int k = n - 1; k >= 2; k--) {
if (k < n - 1 && nums[k] == nums[k + 1])
continue;//去重优化,可以不去
int i = 0, j = k - 1;
while (i < j) {
int sum = nums[i] + nums[j] + nums[k];
if (sum - target == 0)
return sum;
if (min_dis > abs(sum - target)) {
min_dis = abs(sum - target);
ans = sum;
}
if (sum - target > 0) {
j--;
}
else i++;
}
}
return ans;
}
};
cpp
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n=nums.size();
sort(nums.begin(),nums.end());
vector<vector<int>> ans;
for(int i=0;i<n-3;i++){
if(i>0&&nums[i]==nums[i-1]) continue;
for(int j=i+1;j<n-2;j++){
if(j>i+1&&nums[j]==nums[j-1]) continue;
int k=j+1;int m=n-1;
while(k<m){
long long sum=nums[i]+nums[j]+nums[k]+nums[m];
if(sum==target){
ans.push_back({nums[i],nums[j],nums[k],nums[m]});
for (k++; k < m && nums[k] == nums[k - 1]; k++); // 跳过重复数字
for (m--; m > k && nums[m] == nums[m + 1]; m--);
}
else if(sum<target){
k++;
}
else m--;
}
}
}
return ans;
}
};
cpp
class Solution {
public:
int triangleNumber(vector<int>& nums) {
//有效三角形,a+b>c;a-b<c;
sort(nums.begin(),nums.end());
int n=nums.size();
int i,j,k;
int ans=0;
//如果a+b>c;--->a+b+n>c;---->如果a,b>c,则会有b-a-1个
for(k=n-1;k>1;k--){
i=0;j=k-1;
while(i<j){
int sum=nums[i]+nums[j]-nums[k];
if(sum>0){
ans=ans+j-i;
j--;//sum应该变小
}
else //sum<0;数应该变大;
i++;
}
}
return ans;
}
};