【leetcode】15 3sum

前言

最近在刷leetcode,刷题的过程不免遇到一些感觉很困难的题目,在此记录一下解法与思路。

题目描述

https://leetcode-cn.com/problems/3sum/description/
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

解法1

最容易想到的解法就是暴力解法
首先将数组排序,然后三重循环遍历,找到满足条件的元素。
最后还需要对结果再次排序并去重。
由于三个元素,时间复杂度为O(n^3),但如果数组数据量过大,提交会超时。

vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>>  res;
    sort(nums.begin(),nums.end());
    for (int i = 0; i < nums.size(); i ++)
    {
        for (int j = i + 1; j < nums.size(); j ++)
        {
            for (int k = j + 1; k < nums.size(); k ++)
            {
                if (nums[i] + nums[j] + nums[k] == 0){
                    res.push_back({nums[i],nums[j],nums[k]});
                }
            }
        }
    }

    //先排序再去重
    sort(res.begin(),res.end());
    res.erase(unique(res.begin(),res.end()),res.end());
    return res;
}

解法2

使用map来保存数组元素及每个元素的个数。
然后对数组进行排序与去重。
最后进行双重循环,再在map中查找第三个值。
时间复杂度:O(n^2)。

vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>>  res;
    unordered_map<int,int> map1;
    for(int e:nums)
        map1[e] ++;
    
    //特殊情况单独处理
    if (map1[0] >= 3)
        res.push_back({0,0,0});

    sort(nums.begin(),nums.end());
    nums.erase(unique(nums.begin(),nums.end()),nums.end());

    for (int i = 0; i < nums.size(); i ++)
    {
        for (int j = i + 1; j < nums.size(); j ++)
        {
            //由于不存在三个同样的非零值和为0
            //但存在两个同样的非零值与其他值的和为0
            //需要对这种特殊情况单独作判断
            if (map1[nums[i]] >= 2 && nums[i] * 2 + nums[j] == 0)
                res.push_back({nums[i],nums[i],nums[j]});
            if (map1[nums[j]] >= 2 && nums[j] * 2 + nums[i] == 0)
                res.push_back({nums[i],nums[j],nums[j]});

            //如果存在c值,且需要保证c值位置在j之后,不能使用已经遍历过的元素
            int c = 0 - nums[i] - nums[j];
            if (map1[c] > 0 && c > nums[j]){
                res.push_back({nums[i],nums[j],c});
            }
        }
    }

    return res;
}

解法3

这是推荐的解法,首先进行最外层遍历。
内层采用对撞指针的方法,进行遍历。
时间复杂度:O(n^2)。

vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>>  res;
    if(nums.empty() || nums.size() < 3)
        return res;
    sort(nums.begin(),nums.end());
    for (int i = 0; i < nums.size() - 2; i ++)
    {
        int tar = 0 - nums[i];
        /*
         * 以下为获取两个数和为tar
         * 对撞指针,向中间移动
         */
        int j = i + 1,k = nums.size() - 1;
        while (j < k)
        {
            if (nums[j] + nums[k] == tar){//若和等于tar时,则可保存数据
                res.push_back({nums[i],nums[j ++],nums[k --]});
                while(j < k && nums[j] == nums[j - 1])//  若有相等的,则向右移动
                    j ++;
                while(j < k && nums[k] == nums[k + 1])//  若有相等的,则向左移动
                    k --;
            }else if (nums[j] + nums[k] > tar){//若和大于tar,则需要较大值减小,右边界向左移动
                k --;
            }else{//若和小于tar,则需要较小值增大,左边界向右移动
                j ++;
            }
        }
        //保证下一个为不重复的数据
        while (i < nums.size() - 2 && nums[i] == nums[i + 1])
            i ++;
    }
    return res;
}
posted @ 2018-08-21 02:45  JESSET  阅读(205)  评论(0编辑  收藏  举报