一、两数之和 II - 输入有序数组
167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)
思路
数组有序是「双指针」的核心信号:
- 暴力解:嵌套
for循环,时间复杂度 O ( n 2 ) O (n²) O(n2),包超时 - 最优解:双指针(
O
(
n
)
O (n)
O(n) 时间 +
O
(
1
)
O (1)
O(1) 空间),利用数组递增特性,左指针从左,右指针从右向中间收敛,通过和与
target的比较调整指针
复杂度分析
- 时间复杂度: O ( n ) O (n) O(n),双指针仅遍历数组一次
- 空间复杂度:
O
(
1
)
O (1)
O(1),仅使用
left/right两个变量,无额外空间开销
坑点
题目要求返回1 ≤ index1 ≤ index2 ≤ n,在返回时要对指针 + 1
C++ 知识点
- 初始化列表:C++11 的
{}是std::initializer_list语法糖,可快速初始化vector,比push_back更高效 - 有序数组的双指针:“两端收敛” 是有序数组找目标和的通用解法,可迁移到多数有序数组求和问题
代码
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left = 0, right = numbers.size() - 1;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum > target) right--; // 和过大 右指针左移
else if (sum < target) left++; // 和过小 左指针右移
else return {left + 1, right + 1}; // 坑
}
return {};
}
};
二、三数之和
思路
将三数之和转化为「两数之和」问题:
- 排序数组( O ( n l o g n ) O (nlogn) O(nlogn)),为双指针和去重打基础
- 枚举
nums[i],找nums[left] + nums[right] = -nums[i](left=i+1,right=n-1) - 双指针收敛找目标和,同时通过 “跳过重复值” 避免结果重复
复杂度分析
- 时间复杂度: O ( n 2 ) O (n²) O(n2)(排序 O ( n l o g n ) O (nlogn) O(nlogn) + 双指针遍历 O ( n 2 ) O (n²) O(n2)
- 空间复杂度:
O
(
l
o
g
n
)
O (logn)
O(logn)(
std::sort的栈空间开销)
坑点
- 去重逻辑:基准数
nums[i]需判断i>0 && nums[i]==nums[i-1]left/right需要跳过连续重复值 - 边界条件:数组长度 < 3 时直接返回空,避免越界
- 指针移动:找到有效解后,去重需停在最后一个重复值,再移动指针找下一组解
优化
排序后若nums[i] > 0,直接 break:数组递增,后续所有数≥nums [i],三数之和必 > 0
C++ 心知识点
- 二维
vector构造:ret.push_back({a,b,c})依赖 C++11 初始化列表,底层是std::initializer_list(只读数组,不可修改) sort排序:std::sort默认升序,基于快排实现,空间复杂度O (logn)
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
int n = nums.size();
if (n < 3) return ret; // 边界条件:长度不足直接返回
sort(nums.begin(), nums.end()); // 排序是双指针的基础
for (int i = 0; i < n; ++i) {
if (i > 0 && nums[i] == nums[i-1]) continue; // 跳过重复基准数
if (nums[i] > 0) break; // 优化:三数和必>0 直接终止
int left = i + 1, right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum > 0) right--; // 和过大 右指针左移
else if (sum < 0) left++; // 和过小 左指针右移
else {
ret.push_back({nums[i], nums[left], nums[right]});
// 跳过left/right重复值,避免结果重复
while (left < right && nums[left] == nums[left+1]) left++;
while (left < right && nums[right] == nums[right-1]) right--;
// 移动指针找下一组解(离开重复值)
// [-1,0,0,1,1]
left++;
right--;
}
}
}
return ret;
}
};
581

被折叠的 条评论
为什么被折叠?



