(刷题记录6)三数之和

news2024/10/24 21:20:09

三数之和

  • 题目信息:
  • 题目思路(环境来自力扣OJ的C++):
    • 暴力枚举:
    • 双指针:
      • 在三数之和上:
      • 转化成的两数之和:
      • 两数之和小优化:
  • 复杂度:
  • 代码和解释:
    • 暴力枚举:
    • 双指针:

题目信息:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目参考:力扣:15. 三数之和

题目思路(环境来自力扣OJ的C++):

暴力枚举:

使用三层循环,先排序保证重复出现的三元组位置相同,之后依次遍历统计出三个数相加等于 0 的再放入 set 去重。

双指针:

在三数之和上:

  1. 先排序,方便移动去重与使用双指针。

  2. 因为排序相同的数是集中在一起的,可以判断将相同的数跳过。

  3. 使用第一层循环固定一个数,此时问题可以转化为 两数之和(nums[j] + nums[k] = - nums[i])

转化成的两数之和:

我们发现:

  1. 在升序排序状态下,下标向右移动,指向的元素一定会增大或不变,向左移动元素一定会减小或不变(单调性),使用对撞指针可以利用这一特性。

  2. 如果两数之和大于 target (也就是 - nums[i]),要保证 和 的结果一定会减小或不变(为了接近 target),需要 右指针 向左移动,这时优化了没有必要的左指针向右移动

  3. 如果两数之和小于 target,要保证 和 的结果一定会增大或不变,需要 左指针 向右移动,这时优化了没有必要的右指针向左移动

  4. 对撞指针移动时,并不会出现回退的情况,也就是指针移动规则具有单调性,则双指针的使用有效。

  5. 由于题目要求去重,上述相同元素需要跳过。

  6. 注意,固定的 target 的下标 i 与之前也被固定的数不可以在对撞指针范围内,不然会出现重复元素,这里使用的是从大到小固定,则开始时 right = i - 1。
    在这里插入图片描述

两数之和小优化:

  1. 当两个最大的数都小于 target,也就是 right = i - 1, arr[right] + arr[right - 1] < target 时,其他两个数的和一定会小于 target,可以直接退出。
  2. 当两个最小的数都大于 target,也就是 left = 0, arr[left] + arr[left + 1] > target 时,其他两个数的和一定会大于 target,可以直接退出。

复杂度:

暴力枚举:
时间复杂度:O(N ^ 3)
空间复杂度:O(logN)

双指针:
时间复杂度:O(N ^ 2)
空间复杂度:O(logN)

代码和解释:

暴力枚举:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {    // 暴力超时 O(N ^ 3) 
        sort(nums.begin(), nums.end());                      // 排序 
        set<vector<int>> set;                                // 去重准备
        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[j] + nums[k] == 0)
                    {
                        set.insert({nums[i], nums[j], nums[k]}); // 插入去重
                    }
                }
            }
        }
        vector<vector<int>> ans(set.begin(), set.end());     
        return ans;                                          // 返回答案
    }
};

双指针:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {       // 双指针 O(N ^ 2)
        sort(nums.begin(), nums.end());                     // 排序
        vector<vector<int>> ans;
        for (int i = nums.size() - 1; i >= 2; --i)
        {
            int target = -nums[i];                          // 将三数之和转化为两数之和
            int left = 0;
            int right = i - 1;
            bool flag = true;
            if (nums[right] + nums[right - 1] < target
            || nums[left] + nums[left + 1] > target)        // 小优化
            {
                flag = false;
            }

            while (flag && left < right)                    // 对撞指针 + 移动去重
            {
                if (nums[left] + nums[right] == target)     // 相等存入答案
                {
                    ans.push_back({nums[left++], nums[right--], nums[i]});
                }
                else if (nums[left] + nums[right] > target) // 大于时右指针移动反之左指针移动
                {
                    --right;
                }
                else                
                {
                    ++left;
                }

                while (left < right && left > 0 && nums[left] == nums[left - 1])
                {
                    ++left;     // 左去重
                }
                while (left < right && right < i - 1 && nums[right] == nums[right + 1])
                {
                    --right;    // 右去重
                }
            }
            while (i > 2 && nums[i] == nums[i - 1]) // 去重
            {
                --i;
            }
        }
        return ans;        
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言】深入理解指针(三)(上)

本篇博客将讲解以下知识&#xff1a; 1、字符指针变量 2、数组指针变量 1、字符指针变量 在指针的类型中&#xff0c;有一种指针类型为字符指针&#xff1a;char* 一般使用&#xff1a; 注意&#xff1a;%s打印字符串的时候&#xff0c;需要提供字符串首元素的起始地址。 易错…

tensorflow + pygame 手写数字识别的小游戏

起因&#xff0c; 目的: 很久之前&#xff0c;一个客户的作业&#xff0c;我帮忙写的。 今天删项目&#xff0c;觉得比较简洁&#xff0c;发出来给大家看看。 效果图: 1. 训练模型的代码 import sys import tensorflow as tf# Use MNIST handwriting dataset mnist tf.kera…

C# 中循环的应用说明

一循环的概念说明 在C#编程中&#xff0c;循环结构是一种非常重要的控制流语句&#xff0c;它允许我们重复执行一段代码&#xff0c;直到满足某个特定条件为止。C#提供了几种不同类型的循环结构&#xff0c;包括for循环、while循环、do-while循环和foreach循环。 循环语句允许…

树莓派应用--AI项目实战篇来啦-7.OpenCV脸部和眼睛检测

1. 介绍 在深度学习时代&#xff0c;人脸识别一般是利用卷积神经网络进行监督式学习&#xff0c;也就是通过让算法&#xff08;神经网络&#xff09;自己去发现规律的方式&#xff0c;创造出有用的卷积核&#xff0c;然后利用其进行寻找图片和视频中的人脸&#xff0c;而在这之…

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成&#xff0c;打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣&#xff1a;下载软件2️⃣&#xff1a;安装JDK&#xff0c;根据下图操作步骤提示完成安装3️⃣&#xff1a;安装DBeaverEE&#…

【ESP32】ESP-IDF开发 | LED PWM控制器+呼吸灯例程

1. 简介 LED PWM控制器&#xff0c;简称LEDC&#xff0c;主要用于控制LED的亮度和颜色&#xff0c;当然也可以当作普通的PWM进行使用。 LEDC有16路通道&#xff0c;8路高速通道和8路低速通道&#xff0c;16路通道都能够产生独立的数字波形来驱动LED设备。高速和低速通道分别有8…

C++:模拟stack、queue

目录 容器适配器 定义 特点 deque deque的优势与缺点 选择deque作为stack和queue的底层默认容器的原因 模拟实现stack 模拟实现queue 容器适配器 定义 在C标准模板库&#xff08;STL&#xff09;中&#xff0c;容器适配器&#xff08;Container Adapters&#xff09;是…

Harmony开发基础

背景介绍 鸿蒙系统的开发一来是为了打破国外垄断&#xff0c;实现操作系统的国产化&#xff0c;另一方面是针对目前市场上出现大量新的移动设备&#xff0c;手表&#xff0c;折叠屏等&#xff0c;移动端程序要适配不同设备&#xff0c;需要维护一套代码下的多个版本&#xff0…

U盘直接拔掉之后数据丢失怎么恢复 U盘数据丢失了怎么恢复

U盘作为一种存储设备&#xff0c;可以帮助人们存储很多资料文件&#xff0c;无论是办公文件&#xff0c;亦或是生活中的照片&#xff0c;所以在存储数据文件时&#xff0c;人们是比较依赖U盘。不过&#xff0c;U盘也存在很多的不确定性&#xff0c;比如数据容易丢失、或者损坏。…

NirCmd-sendkeysendkeypress

引入script [Script File] This command allows you to execute a sequence of commands stored inside the file specified in [Script File] parameter. Example: script "c:\temp\msg.ncl" Example for a script:infobox "Hello !" "This is the …

微知-如何查看服务器CPU当前运行主频?(cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq)

关键命令 cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq背景 首先lscpu可以查看到有多个cpu&#xff0c;里面也会显示cpu的频率&#xff0c;但是这里显示仅仅是规格&#xff0c;不是实际值。为了查看实际值&#xff0c;需要到/sys文件系统中查看&#xff0c;也…

大数据-167 ELK Elasticsearch 详细介绍 特点 分片 查询

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

ARIMA 模型初体验 —— 预测股票数据

第 1 步&#xff0c;从 twelvedata 上获取苹果 11 号 15:30 到 16:00 的 OHLC、成交量 数据。 第 2 步&#xff0c;编写 Python 代码&#xff08;实际上可以用 R 语言&#xff0c;R 语言从语言的级别对分析预测提供了支持&#xff0c;而 Python 需要第三方库&#xff09;。 …

Yolov8 搭配 Frequency-aware Feature Fusion for Dense Image Prediction

个人觉得论文赞的地方 https://github.com/Linwei-Chen/FreqFusion https://www.arxiv.org/abs/2408.12879 因为我有个项目需要训练边界模糊的情况,但又需要目标能在模糊里凸显出来,就是看到这张图以后觉得很赞,边界变得清晰有特征是我想要的,所以尝试用了 使后感 哈哈…

【CSS3】css开篇基础(2)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

数据结构-5.2.树的性质

一.树的常考性质&#xff1a; 性质1&#xff1a;结点数 总度数 1(结点的度&#xff1a;结点分支的数量) 一个分支中&#xff0c;如父结点B&#xff0c;两个子结点为E和F&#xff0c;结点B的度的值为2&#xff0c;等于子结点数量&#xff0c;加上这一个父结点(父结点只能有一…

【计算机网络 - 基础问题】每日 3 题(三十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

大型语言模型(LLMs)关键技术指南

在AI这个超火的领域&#xff0c;打好基础真的超级重要&#xff0c;尤其是当你开始研究那些超大型的语言模型&#xff0c;也就是LLMs的时候。这个指南就是想帮新手们把那些听起来高大上的概念变得简单易懂&#xff0c;比如神经网络、自然语言处理&#xff08;NLP&#xff09;还有…

【ROS2实操一】话题通信与自定义消息

一、准备工作 1.请先创建工作空间 mkdir -p ws01_plumbing/src //创建工作空间 colcon build //在工作空间目录下编译 2.创建专门的接口功能包定义接口文件(需要注意的是&#xff0c;目前为止无法在Python功能包中定义接口文件)&#xff0c;终端下进…

线程基础学习

线程的实现 通过实现Runnable接口的方式&#xff0c;实现其中的run方法。继承Thread类&#xff0c;然后重写其中的run方法。通过线程池创建线程&#xff0c;默认采用DefaultThreadFactory。有返回值的callable&#xff0c;实现callable接口&#xff0c;实行call方法。 本质上…