zoukankan      html  css  js  c++  java
  • [leetcode数组系列]2三数之和

    文章首发于公众号[我是程序员小贱]

    前言

    秋招的结束,面试了大大小小的公司,最大的问题在于算法上。所以打算坚持在leetcode打卡,看看到底能不能行,如果你想见证,那我来开车,你坐稳,一起走向更好的远方。

    在学习今天内容之前,先学习上一篇的两数之和会更好哟
    leetcode两数之和求解

    一 题目

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

    1 leetcode链接

    https://leetcode-cn.com/problems/3sum/

    示例

    例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

    满足要求的三元组集合为:
    [
    [-1, 0, 1],
    [-1, -1, 2]
    ]

    2 思路1---暴力解法

    在思考两数之和解决方法的时候,我们使用了两层循环把所有的结果给求出来,相信读者很快就想到三数之和我就用三个循环,很棒,思路是一样,只是之前的a+b=0,现在的b=c+d了。好了代码呈上。

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            if(nums.size()<3) return{};
            vector<vector<int>> res;//结果
            set<vector<int>> ret;//用来去重
            for(int i=0;i<nums.size()-2;i++)
            {
                for(int j=i+1;j<nums.size()-1;j++)
                {
                    for(int k=j+1;k<nums.size();k++)
                    {
                        if(nums[i]+nums[k]+nums[j]==0)
                        {
                            vector<int> tp;
                            int a=(nums[i]<nums[j]?nums[i]:nums[j])<nums[k]?(nums[i]<nums[j]?nums[i]:nums[j]):nums[k];//放最小的元素
                            int b=(nums[i]>nums[j]?nums[i]:nums[j])>nums[k]?(nums[i]>nums[j]?nums[i]:nums[j]):nums[k];//放最大的元素
                            int c=0-a-b;
                            tp.push_back(a);
                            tp.push_back(c);
                            tp.push_back(b);
                            ret.insert(tp);
                        }
                    }
                }
            }
            for(auto it:ret)
            {
                res.push_back(it);
            }
            return res;
        }
    };
    

    3 思路2---排序加双指针

    • 第一步将整个数组排序,如下图。
      在这里插入图片描述

    • 从左侧开始,选定第一个数为定值比如下面的-4,然后左右指针分别指向对应位置如下图,是不是很像快排。
      在这里插入图片描述

    • 定义的左右和定值相加

      • 如果等于0,记录下三个值
      • 如果小于0,左指针右移动
      • 如果大于0,右指针左移
    • 然后定值右移,重复这个步骤

    下面先看看整体的代码,随后图解整个代码流程以及如何处理重复的情况

    c++版本

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
             int target;
            vector<vector<int>> ans;
            sort(nums.begin(), nums.end());
            for (int i = 0; i < nums.size(); i++) {
                if (i > 0 && nums[i] == nums[i - 1]) continue;
                if ((target = nums[i]) > 0) break;
                int left = i + 1, right = nums.size() - 1;
                //取出三个数 所以不用left=right
                while (left < right) {
                    if (nums[left] + nums[right] + target < 0) ++left;
                    else if (nums[left] + nums[right] + target > 0) --right;
                    else {
                        ans.push_back({target, nums[left], nums[right]});
                        ++left, --right;
                        //去重 
                        //测试数据[-2,0,0,2,2]
                        while (left < right && nums[left] == nums[left - 1]) ++left;
                        while (left < right && nums[right] == nums[right + 1]) --right;
                    }
                }
            }
            return ans; 
        }
    };
    

    一次循环的图解

    在这里插入图片描述
    如果有重复数,怎么去重的呢。如果测试数据为[-2,0,0,2,2]。

    在这里插入图片描述
    我想起在参考招聘要求的时候有句话是熟悉c/c++,java之一,同时了解python等脚本更好,所以在此放上python的方法。

    python版本

    class Solution:
        def threeSum(self, nums: List[int]) -> List[List[int]]:
    
            nums.sort()
            n = len(nums)#获取列表长度
            res = []#存放结果
    
            for i in range(n):
                if i > 0 and nums[i] == nums[i-1]:
                    continue
                num1 = nums[i]#取得定值
                if num1 > 0:
                    break
                #定义双指针初始状态
                j = i + 1
                k = n - 1
                while j < k:
                    total = num1 + nums[j] + nums[k]
                    if total == 0:
                        res.append((num1, nums[j], nums[k]))
                        j += 1
                        while nums[j] == nums[j-1] and j < k:
                            j += 1
                        k -= 1
                        while nums[k] == nums[k+1] and j < k:
                            k -= 1
                    elif total > 0:
                        k -= 1
                        while nums[k] == nums[k+1] and j < k:
                            k -= 1
                    else:
                        j += 1
                        while nums[j] == nums[j-1] and j < k:
                            j += 1
            return res
    

    4 总结

    文中使用了两种方式来解决这个问题,第一种为复杂度较高的暴力解答,第二种使用了类似快排思想的双指针法,后面还会有更多关于双指针的用法,敬请期待。至此,想想有学会点什么了?

    5 结尾

    希望读者和咱一起一步一个脚印去把基础知识打牢固。如果读者发现有什么错误或者不太好的地方,欢迎私我,我会及时修改。如果觉得不错或者方便手机上查看可以在下面公众号温故复习哟!

    img

  • 相关阅读:
    Python入门系列——第20篇
    Python入门系列——第19篇
    windows下python使用pip命令安装builtwith库时,遇到的utf-8问题的解决
    Python入门系列——第18篇
    在相同的主机上创建一个duplicate数据库
    duplicate database的时候,rman连接 auxiliary database的后状态不正确
    使用duplicate target database ... from active database复制数据库
    RHEL7
    Oracle 监听器日志文件过大导致监听异常
    TNS-01251: Cannot set trace/log directory under ADR
  • 原文地址:https://www.cnblogs.com/lanjianhappy/p/12142024.html
Copyright © 2011-2022 走看看