3Sum
Solution 1
这个题非常常见了,主要就是处理好双指针,这个题应该经常用来考双指针。这个题主要处理的问题是重复元组的处理。首先给整个序列排序,顺序枚举第一个加数,后面两个加数从其后面的数列中进行遍历。重复元组的判定可以通过相同的数字判断:如果第一个加数与过去枚举的结果相同,那么后面必然都会相同;后面两个加数同理。而经过排序后,相同元素的判断就变得方便了:想更大往后看,想更小往前看,相同就是相同不会漏掉。
- 时间复杂度: O ( N 2 ) O(N^2) O(N2),其中排序为 O ( N log N ) O(N \log N) O(NlogN), 一层遍历 O ( N ) O(N) O(N),双指针维护 O ( N ) O(N) O(N), N N N为数组长度
- 空间复杂度: O ( log N ) O(\log N) O(logN), N N N为数组长度,寻找算法的状态量为常数个,但是排序算法需要辅助空间
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
if (nums.size() < 3) {
return ans;
}
for (int posA = 0; posA < nums.size(); ++posA) {
// 过滤重复的情况,如果第一个数字一样,这个数字的所有可能情形已经全部覆盖,会造成重复
if (posA > 0 && nums[posA] == nums[posA - 1]) {
continue;
}
if (posA > nums.size() - 3) {
break;
}
int posB = posA + 1;
int posC = nums.size() - 1;
// 双指针维护
while (posB < posC) {
int sum = nums[posA] + nums[posB] + nums[posC];
if (sum == 0) {
ans.push_back({nums[posA], nums[posB], nums[posC]});
posB++;
posC--;
// 对两个指针也去重
while (posB < posC && nums[posB] == nums[posB - 1]) {
posB++;
}
while (posB < posC && nums[posC] == nums[posC + 1]) {
posC--;
}
}
// 负的一项太大了,选一个更小的
else if (sum < 0) {
posB++;
}
// 正的项太大了,选个更小的
else {
posC--;
}
}
}
return ans;
}
};
Solution 2
Solution 1 的Python实现
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums_ordered = sorted(nums)
ans = []
if len(nums_ordered) < 3:
return ans
for posA in range(len(nums_ordered) - 2):
if posA > 0 and nums_ordered[posA] == nums_ordered[posA - 1]:
continue
posB = posA + 1
posC = len(nums_ordered) - 1;
while posB < posC:
nums_sum = nums_ordered[posA] + nums_ordered[posB] + nums_ordered[posC]
if nums_sum == 0:
ans.append([nums_ordered[posA], nums_ordered[posB], nums_ordered[posC]])
posB += 1
posC -= 1
while posB < posC and nums_ordered[posB] == nums_ordered[posB - 1]:
posB += 1
while posB < posC and nums_ordered[posC] == nums_ordered[posC + 1]:
posC -= 1
elif nums_sum < 0:
posB += 1
else:
posC -= 1
return ans