zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    subString源码分析
    我的three.js学习记录(三)
    我的three.js学习记录(二)
    2017-10-15
    我的three.js学习记录(一)
    我的Spring学习记录(三)
    我的Spring学习记录(二)
    我的Hibernate学习记录(二)
    我的Hibernate学习记录(一)
    Tomcat学习笔记
  • 原文地址:https://www.cnblogs.com/JesseTsou/p/9509145.html
Copyright © 2011-2022 走看看