15. 三数之和 关于数组多重遍历的一些想法

题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

二重遍历的常用化简套路:双指针,用大小关系找出必然的移动规律,通过该规律化简算法。经常 遍历左指针,而右指针作为上限在左指针右移的过程中变化,从而达到O(n)的效果。

双指针常用错指南:while或者for循环出来时两个指针是重和的,出来后如果要处理数据会出现重和的可能。

多重数组遍历的常见易错点:题目要求各个遍历的数之间可以重复吗?如果不能重复,又如何处理所给数组中有重复数的情况呢?可以通过在遍历时与前面的数比较了实现。

分析: 三个数在数组中进行查找,一个循环不变,另外两个数的遍历可以使用双指针(因为三个数中间的大小关系比较紧密)来降低时间复杂度。

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<vector<int>> threeSum(vector<int>& nums){
    int total = nums.size();
    vector<vector<int>> res;
    if(total < 3){
        return res;
    }
    sort(nums.begin(), nums.end());
    for (int i = 0; i < total; i++){
        if (i > 0 && nums[i] == nums[i-1]){
            continue;//如何跳过重复的数字
        }
        if(nums[i]>0){
            break;
        }
        int end = total -1;
        for (int j = i + 1; j < end; j++){
            //双指针,遍历左边, 则每种情况只能变化右边, 有点像动态规划,可以先定下来可以这样做事对的
            //循环其实也可以进行假设我的这个函数前后都是对的,然后设计中间步骤,类似于递归,动态规划
            //由于在第二各遍历过程中,两个数中间的大小联系比较突出, 可以考虑用双指针进行简化遍历查找结果
            if(j > i+1 && nums[j] == nums[j-1]){
                continue;
            }
            while(end > j && nums[j]+nums[end]+nums[i] > 0){
                end--;
            }
            //这种while或者for循环套--的最后结果可能是会两者重和, 注意
            //如果要处理这些后面的数据, 注意考虑到重和的情况
            if(end == j){
                break;
            }
            if(nums[i]+nums[j]+nums[end] == 0){
                static vector<int> tempRes;
                tempRes.push_back(nums[i]);
                tempRes.push_back(nums[j]);
                tempRes.push_back(nums[end]);
                res.push_back(tempRes);
            }
        }
    }
    return res;
}

int main(void){
    vector<int> a;
    int b[] = {-1, 0, 1, 2, -1, -4};
    a.insert(a.begin(), b, b + 6);
    vector<vector<int>> res = threeSum(a);
    for (int i = 0; i < res.size(); i++){
        printf("[%d, %d, %d], ", res[i][0], res[i][1], res[i][2]);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值