《LeetCode》—— LeetCode刷题日记

news2024/12/29 10:55:01

本期,我给大家讲述的是关于 n数之和这类题目的讲解,我会给大家讲解两数之和,三数之和和四数之和这三道题目。


目录

(一)两数之和

(二)三数之和

(三)四数之和


(一)两数之和

链接如下:两数之和

题目如下:

 

题意分析:

要解决查找两个数字之和的问题,可以通过遍历数组并检查每个可能的数字对来使用暴力方法。然而,这种方法的时间复杂度为 O(n^2),效率不高。

💨 解决方法:

  1.  更好的方法是使用哈希表将数组的值存储为键,将其索引存储为值;
  2. 然后,对于数组中的每个数字,可以检查哈希表中是否存在目标总和与当前数字之间的差异;
  3. 如果存在,那么表示就已经找到了加起来等于目标总和的数字对。这种方法的时间复杂度为 O(n),效率更高。

具体步奏:

step 1:构建一个哈希表,用于记录各值和值对应的下标;

step 2:检查哈希表中是否存在目标总和与当前数字之间的差异:

  • 如果存在说明我们先前遍历的时候它出现过,根据记录的下标,我们返回两个数字的索引,就可以得到结果;
  • 如果没有,我们将当前数字及其索引添加到哈希表中

代码展示:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int size = nums.size();
        vector <int> res;
        if (!size)
            return res;
        // 定义哈希表
        unordered_map<int, int> tmp;

        for (int i = 0; i < size; i ++) {
            if (tmp.find(target - nums[i]) != tmp.end()) 
            { 
                // find函数返回tmp.end()代表未找到,否则代表找到
                // 将结果存入数组
                res.push_back(tmp[target - nums[i]]);
                res.push_back(i);
                break;
            } 
            else 
            {
                tmp[nums[i]] = i; // 将未找到的值插入哈希表中,继续遍历
            }
        }
        return res;
    }
};

性能分析:

  • 时间复杂度:O(n),仅仅遍历数组一次,每次查询哈希表都是O(1)
  • 空间复杂度:O(n),最坏情况下找到数组结尾才找到,其他都加入哈希表,因此哈希表最长为n−1的长度

(二)三数之和

链接如下:三数之和

题目如下:

 

题意分析:

  1. 本题跟上述两数之和的题目类似。为了解决“三数之和”问题,我们可以使用两指针方法;
  2. 首先,我们按非降序对输入数组进行排序。然后,我们使用 for 循环遍历数组,对于每个元素,我们使用两个指针来查找另外两个元素,它们的总和为当前元素的负数;
  3. 如果我们找到这样的三元组,我们将其添加到我们的结果向量中。为了避免重复,我们跳过任何重复的元素。

具体步奏:

step 1我们对这个无序的数组进行排序操作,使用sort函数优先对其排序;

step 2:紧接着遍历该数组,对于三个数字都要判断是否相邻有重复的情况,因此要对其进行去重操作;

step 3:对于每个遍历到的元素假设它是三元组中最小的一个,那么另外两个一定在后面;

step 4:接下来,使用双指针的思想遍历去数组,因为最后得到的和为0,找到两个位置处的元素之和等于开始定义的最小值的相反值;

step 5:如果二者相加大于目标值,说明右指针太大了,那就将其左移缩小,相反如果二者相加小于目标值,说明左指针太小了,将其右移扩大,直到两指针相遇为止。

代码展示:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        // 按升序对输入向量进行排序
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i++) 
        {
            //检查它是否是前一个元素副本,如果是重复项,循环将跳到下一个元素。
            if (i > 0 && nums[i] == nums[i-1]) 
                continue;
            //如果当前元素不是重复的,将目标值设置为当前元素的负值
            int target = -nums[i];
            //然后,将两个指针(左和右)分别初始化到向量中的下一个元素和最后一个元素。
            int left = i+1, right = nums.size()-1;
            //只要左小于右,该循环就会继续
            while (left < right) 
            {
                //检查左右值的总和是否等于目标值
                if (nums[left] + nums[right] == target) 
                {
                    //如果是,将三个值的向量添加到结果向量中
                    result.push_back({nums[i], nums[left], nums[right]});
                    //然后,向左递增,向右递减。
                    left++;
                    right--;

                    while (left < right && nums[left] == nums[left-1]) left++;
                    while (left < right && nums[right] == nums[right+1]) right--;
                } 
                //如果左侧和右侧的值之和小于目标值,则函数向左递增
                else if (nums[left] + nums[right] < target) 
                {
                    left++;
                } 
                //如果它大于目标值,则函数向右递减
                else 
                {
                    right--;
                }
            }
        }
        //最后,该函数返回包含所有唯一三元组的结果向量,这些三元组的总和为零
        return result;
    }
};

性能分析:

  • 时间复杂度:O(n^2),其中 n 是输入数组的长度。此实现使用两个嵌套循环遍历所有可能的数字对,并使用哈希表来检查数组中是否存在完成三元组所需的第三个数字,所以时间复杂度为O(n^2);
  • 空间复杂度:O(N)。

(三)四数之和

链接如下: 四数之和

题目如下:

 

题意分析:

同“三数之和”一样,如果通过遍历数组并检查每个可能的数字这种暴力方法,那么时间时间复杂度将达到O(N^4)。因此,还是跟上述一样整体思路是使用嵌套循环和两个指针来循环访问数组并查找四个元素。

题意涉及在数组中查找所有唯一的“四胞胎”,这些四胞胎的总和等于给定的目标值。

具体步奏:

step 1我们对这个无序的数组进行排序操作,使用sort函数优先对其排序;

step 2:注意这里因为是四个数,因此需要注意区间的变化情况;

step 3:紧接着遍历该数组,对于四个数字都要判断是否相邻有重复的情况,因此要对其进行去重操作;

step 4:接下来,使用双指针的思想遍历去数组,如果最后得到的和等于target,记录下来,但是四者中间的数字相加可能还会有;

step 5:如果四者相加大于目标值,说明右指针太大了,那就将其左移缩小,相反如果四者相加小于目标值,说明左指针太小了,将其右移扩大,直到两指针相遇为止。

代码展示:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
    vector<vector<int>> res;
    if (nums.empty()) 
        return res;
    //首先按升序对输入数组进行排序,这允许在迭代过程中有效地跳过重复值
    sort(nums.begin(), nums.end());

    int n = nums.size();
    //外部循环遍历四个数中的前三个整数
    for (int i = 0; i < n - 3; i++) 
    {
          if (i > 0 && nums[i] == nums[i - 1]) 
            continue;
        //内部循环访问第四个整数
        for (int j = i + 1; j < n - 2; j++) 
        {
           //去重
            if (j > i + 1 && nums[j] == nums[j - 1]) 
                continue;
            //双指针用于查找总和为目标值的其余两个整数
            int left = j + 1, right = n - 1;
            while (left < right) 
            {
                //检查总和是否等于目标值
               long sum =(long) nums[i] + nums[j] + nums[left] + nums[right];
                if (sum == target) 
                {
                    res.push_back({nums[i], nums[j], nums[left], nums[right]});
                  
                    while (left < right && nums[left] == nums[left + 1]) left++;
                        left++;
                   
                    while (left < right && nums[right] == nums[right - 1]) right--;
                        right--;
                } 
                //和小于目标值,则函左指针向右
                else if (sum < target) 
                {
                    left++;
                } 
                //如果它大于目标值,则右指针向左
                else 
                {
                    right--;
                }
            }
        }
    }
    return res; 
    }
};

性能分析:

  • 时间复杂度:O(N^3),其中 n 是数组的长度。排序的时间复杂度是 O(nlogn),枚举四元组的时间复杂度是 O(N^3),所以时间复杂度为 O(N^3)
  • 空间复杂度: O(N),排序修改了输入数组 nums,实际情况中不一定允许这样的情况发生,因此也可以看成使用了一个额外的数组存储了数组 nums 的副本并排序,空间复杂度为O(N)。

 总体而言,由于嵌套循环,代码的时间复杂度为 O(n^3),但排序步骤降低了常数因子并提高了整体性能。


到此,便是以上题目的全部讲解。希望对大家有所帮助,感谢大家的阅读!!!

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

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

相关文章

NodeJs 最近各版本特性汇总

&#xff08;预测未来最好的方法就是把它创造出来——尼葛洛庞帝&#xff09; NodeJs 官方链接 github链接 V8链接 Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模…

对象应用:C++字符串和vector,对象的new与delete重构

对象应用 C字符串和vector字符串创建方式字符串拼接字符串追加 字符串截断autovector创建方式vector操作 new与delete重构new与delete的工作步骤new与delete重构应用只能生成栈对象只能生成堆对象 C字符串和vector C的字符串是一个对象&#xff0c;存在于std标准库中&#xff0…

Python基础入门(4)—— 什么是偷懒编程法?是类、对象和继承

文章目录 00 | &#x1f603;为什么学习类&#xff1f;&#x1f603;01 | &#x1f604;创建类&#x1f604;02 | &#x1f606;创建对象&#x1f606;03 | &#x1f609;访问对象属性和方法&#x1f609;04 | &#x1f60a;构造函数&#x1f60a;05 | &#x1f60b;继承&#…

Shell编程之数组

目录 一、数组的基本概念 二、定义数组的方法 方法一&#xff1a; ​编辑 方法二&#xff1a; 方法三&#xff1a; ​编辑 方法四&#xff1a; 三、 数组的输出&#xff0c;删除和长度统计 1&#xff09;数组元素的输出 2&#xff09;数组全部元素输出 3&#xff0…

一种用于提高无线传感器网络寿命的改进LEACH协议(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 无线传感器网络具有网络灵活性强、网络规模可变等优点&#xff0c;广泛应用于军事、工业等领域。无线传感器网络的基本网络路由…

Mybatis一级缓存详解

目录 一级缓存 一级缓存的组织 一级缓存的生命周期 一级缓存的工作流程 Cache接口的设计以及CacheKey的定义 一级缓存的性能分析 一级缓存与Spring 事务一级缓存存在的弊端 官方文档分析 Spring通过Mybatis调用数据库的过程 一级缓存 对于会话&#xff08;Session&am…

Nacos-01-Nacos基本介绍

背景 ​ 服务发现是⼀个古老的话题&#xff0c;当应用开始脱离单机运行和访问时&#xff0c;服务发现就诞生了。目前的网络架构是每个主机都有⼀个独立的 IP 地址&#xff0c;那么服务发现基本上都是通过某种方式获取到服务所部署的 IP 地址。DNS 协议是最早将⼀个网络名称翻译…

让AI帮忙写个需求,AI写出来了,只是有bug而已

需求 使用原生JS和iframe&#xff0c;嵌入网页进行轮播&#xff0c;需要可以点击暂停、上一页、下一页。 AI的答案 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>轮播图</title><style>* {margin: 0;padd…

看板项目管理:如何可视化工作以提高生产力?

如果你一直关心优化工作流程&#xff0c;提高你或团队的生产力&#xff0c;你肯定听说过看板这个词。 看板是一种工作管理方法&#xff0c;可以将整个工作流程以及构成工作流程的每个单独活动可视化&#xff0c;从而可以识别瓶颈和优化整体流程。 在这方面&#xff0c;看板的…

Python基础(二)

目录 一、类型转换 1、为什么需要数据类型转换 2、数据类型转化的函数 3、str()函数类型转换使用 4、int()函数类型转换使用 4.1int()不能将str类型数据转换成int 4.2int()将bool类型转换成int 4.3int()将float转换成int 5、Float()函数类型转换使用 5.1Float()函数不…

ros imu可视化(ubantu)

可以用下面的链接安装ros 安装ros 在home下建立workspace&#xff0c;添加环境变量 export $ROS_PACKAGE_PATHROS_PACKAGE_PATH:/home/workspace在workspace下建立src文件夹&#xff0c;将fdilink_ahrs_ROS1解压在src目录下面 在workspace下运行以下命令&#xff1a; catkin_…

【牛客面试必刷TOP101】有效括号序列、滑动窗口的最大值

BM44 有效括号序列 点击进入该题 描述&#xff1a; 给出一个仅包含字符’(‘,’)‘,’{‘,’}‘,’[‘和’],的字符串&#xff0c;判断给出的字符串是否是合法的括号序列。 括号必须以正确的顺序关闭&#xff0c;"()“和”()[]{}“都是合法的括号序列&#xff0c;但”(]“…

(七)如何实现即时通信系统中用户的文字聊天功能?

文章目录 一、引言二、实现用户文字功能2.1 使用QTextEdit控件实现用户输入文字消息2.2 实现文字消息的发送和接收2.3 实现文字消息的展示和管理 三、解码接收到的文字消息3.1 接收数据并解码3.2 在客户端展示文字消息3.3 客户端关键代码展示3.4 服务端关键代码展示 四、效果展…

干货 | 如何做一个简单的访谈研究?

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 心理学中研究中&#xff0c;大家常用的研究方法大多是实验法、问卷调查法等&#xff0c;这些均是定量研究。 其实&#xff0c;作为质性研究中常用的访谈法&#xff0c;可对个体的内心想法进…

【操作系统】从操作系统底层出发,成为更好的程序员

冯老爷子的模型 首先&#xff0c;我们从一个问题开始(&#xffe3;∇&#xffe3;)/ 为什么需要程序员&#xff1f; 早期的计算机程序是硬件化的&#xff0c;即使用各种门电路组装出一个固定的电路板&#xff0c;这个电路板只能用于执行某个特定的程序&#xff0c;如果需要修…

学生电费管理系统

随着现代化的发展和科技的进步&#xff0c;各种智能化的系统应运而生。其中&#xff0c;学生电费管理系统是一个非常实用的系统&#xff0c;它可以帮助学校管理电费&#xff0c;提高学生的电费管理意识&#xff0c;减少学校的电费支出。本文将着重介绍该系统的作用、特点以及优…

【hive】基于Qt5和libuv udp 的lan chat

作者已经不更新了,但是很棒 在线用户列表: 聊天窗口 主程序 单独的网络线程: network_thread data管理关联网络管理的 程序update升级更新 和消息收到 即可

【Java】面试常问知识点(数据库相关知识)

Redis Redis数据结构&#xff0c;跳表如何实现&#xff1f;跳表添加层级的时机&#xff1f; 布隆过滤器的底层原理 Redis数据结构 有5中数据结构&#xff0c;string&#xff08;字符串类型&#xff09;、list&#xff08;列表类型&#xff09;、hash&#xff08;哈希表类型…

Ubuntu 20.04 系统配置 OpenVINO 2022.3 环境

由于 OpenVINO 2021 版本在调用 IECore 时会出现 Segmentation fault 的问题&#xff0c;因此需要将其升级为 2022 版本的。 1. 卸载原来版本的 OpenVINO 进入OpenVINO的卸载目录&#xff0c;通常在 /opt/intel 文件夹下&#xff0c; cd /opt/intel/openvino_2021/openvino_…

SOA协议DDS和Some/IP对比

SOME/IP 和 DDS 均已被纳入AUTOSAR AP的平台标准中。 SOME/IP 和 DDS是在不同的应用场景和不同的需求下诞生的技术&#xff0c;所以它们之间注定有很大的区别。 SOME/IP SOME/IP的全称为&#xff1a;Scalable service-Oriented MiddlewarE over IP&#xff0c;是一种面向服务…