算法题打卡力扣第15题:三数之和(mid)

题目描述


解法一:暴力解

用三个for循坏枚举出所有等于的三元组然后再排序筛选出不同的三元组

代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        std::set<std::vector<int>> resultSet;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                for(int k=j+1;k<n;k++){
                    if(nums[i]+nums[j]+nums[k]==0){
                        std::vector<int> triplet = {nums[i],nums[j],nums[k]};
                        std::sort(triplet.begin(),triplet.end());
                        resultSet.insert(triplet);
                    }
                }
            }
        }
        std::vector<std::vector<int>> finalResult(resultSet.begin(),resultSet.end());
        return finalResult;
    }
};

执行结果:

超出时间限制了。

复杂性分析:

时间复杂度分析:O(n^3)

空间复杂度分析:O(n)

解法二:排序+降维+双指针

a + b + c = 0 等价于 b + c = -a 如果我们能固定一个数 a (即nums[i]),那么问题就转化成了:在数组剩下的部分中,寻找两个数,它们的和等于 -a。 这就变成了我们非常熟悉的 "两数之和" (Two Sum) 问题!

具体步骤:

  • 排序:首先,对整个 nums 数组进行升序排序。这一步至关重要,它是双指针法和去重逻辑的基础。时间复杂度 O(n log n)。
  • 主循环 (固定 a):使用一个 for 循环遍历排序后的数组,i 从 0 到 n-3。nums[i] 就是我们固定的那个数 a。
    优化/剪枝:如果 nums[i] > 0,由于数组已经排序,后面的 nums[left] 和 nums[right] 也必然大于 0,三者之和不可能等于 0。所以,一旦 nums[i] > 0,就可以直接 break 循环了。
    去重 a:这是第一个关键的去重逻辑。如果当前的 nums[i] 和上一个 nums[i-1] 相同,那么以 nums[i] 为基础找到的三元组,必然和以 nums[i-1] 为基础的完全一样。为了避免重复,我们需要跳过这种情况。代码实现:if (i > 0 && nums[i] == nums[i-1]) { continue; }
  • 双指针 (寻找 b 和 c):对于每一个 i,我们在它右边的区间 [i+1, n-1] 内使用双指针。
    初始化左指针 left = i + 1。
    初始化右指针 right = n - 1。
    计算目标和 target = -nums[i]。
  • 移动双指针:进入一个 while (left < right) 循环。
    计算当前和 sum = nums[left] + nums[right]。
    计算当前和 sum = nums [left]+ nums [right]。

情况一:sum == target

我们找到了一个解!将 (nums[i], nums[left], nums[right]) 添加到结果列表中。

去重 b 和 c:这是第二个关键的去重逻辑。在我们找到一组解后,需要同时移动 left 和 right 指针。但如果 nums[left] 的下一个元素和它自己相同,或者 nums[right] 的前一个元素和它自己相同,就会产生重复解。所以,我们需要跳过所有与当前 nums[left] 和 nums[right] 相同的元素。

代码实现:

while (left < right && nums[left] == nums[left+1]) left++;

while (left < right && nums[right] == nums[right-1]) right--;

跳过重复项后,left 和 right 还需要再各前进一步,去寻找下一组不同的解:left++; right--;

情况二:sum < target

和太小了。为了让 sum 变大,我们需要一个更大的数。所以,左指针 left 向右移动:left++。

情况三:sum > target

情况三:sum < 目标

和太大了。为了让 sum 变小,我们需要一个更小的数。所以,右指针 right 向左移动:right--。

  • 循环结束后,返回结果列表。
    g老师
    代码实现:
cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        // 枚举 a
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 需要保证 b 的指针在 c 的指针的左侧
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                // 如果指针重合,随着 b 后续的增加
                // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    ans.push_back({nums[first], nums[second], nums[third]});
                }
            }
        }
        return ans;
    }
};

复杂度分析

时间O(n^2)

空间O(n)

相关推荐
papership7 分钟前
【入门级-数据结构-3、特殊树:完全二叉树的定义与基本性质】
数据结构·算法
中國龍在廣州10 分钟前
AI顶会ICML允许AI参与审稿
人工智能·深度学习·算法·机器学习·chatgpt
立志成为大牛的小牛11 分钟前
数据结构——六十、快速排序(王道408)
数据结构·程序人生·考研·算法·排序算法
Dev7z12 分钟前
基于MATLAB的GA–PSO混合算法无线传感器网络节点部署优化研究
网络·算法·matlab
koo36415 分钟前
12.14周报
人工智能·算法
Dream it possible!26 分钟前
LeetCode 面试经典 150_字典树_添加与搜索单词 - 数据结构设计(96_211_C++_中等)
c++·leetcode·面试·字典树
月明长歌36 分钟前
【码道初阶】Leetcode155踩坑最小栈问题:最小栈:算法对了,却输给了 Java 的 “==“?
java·算法·
我送炭你添花43 分钟前
Pelco KBD300A 模拟器:05.校验算法终极对比 + 完整 100+ 指令封装 + KBD300A 所有隐藏功能函数化
python·算法·自动化·运维开发
DuHz1 小时前
汽车FMCW雷达互扰下的快速目标检测:谱峰累积法与泊松CFAR精读与推导
论文阅读·算法·目标检测·汽车·信息与通信·信号处理
2401_837088501 小时前
算法边界情况处理套路总结
算法