算法题打卡力扣第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)

相关推荐
大千AI助手7 分钟前
Householder变换:线性代数中的镜像反射器
人工智能·线性代数·算法·决策树·机器学习·qr分解·householder算法
Mr.H012719 分钟前
迪杰斯特拉(dijkstra)算法
算法
南方的狮子先生1 小时前
【数据结构】从线性表到排序算法详解
开发语言·数据结构·c++·算法·排序算法·1024程序员节
派大星爱吃猫1 小时前
快速排序和交换排序详解(含三路划分)
算法·排序算法·快速排序·三路划分
焜昱错眩..1 小时前
代码随想录第四十八天|1143.最长公共子序列 1035.不相交的线 53. 最大子序和 392.判断子序列
算法·动态规划
AI妈妈手把手1 小时前
YOLO V2全面解析:更快、更准、更强大的目标检测算法
人工智能·算法·yolo·目标检测·计算机视觉·yolo v2
极客智造1 小时前
编程世界的内在逻辑:深入探索数据结构、算法复杂度与抽象数据类型
数据结构·算法·数学建模
好好学习啊天天向上2 小时前
多维c++ vector, vector<pair<int,int>>, vector<vector<pair<int,int>>>示例
开发语言·c++·算法
MicroTech20252 小时前
MLGO微算法科技 LOP算法:实现多用户无线传感系统中边缘协同AI推理的智能优化路径
人工智能·科技·算法
Greedy Alg2 小时前
Leetcode 279. 完全平方数
算法