LeetCode 热题 100 | 双指针(上)

目录

1  283. 移动零

2  11. 盛最多水的容器

3  15. 三数之和


菜鸟做题第一周,语言是 C++

1  283. 移动零

解题思路:

  1. 两个指针一前一后遍历数组
  2. 前者永远指向 0,后者永远在寻找非 0 数的路上
  3. 后者找到一个非 0 数就和前者进行一个数值交换

思路说明图:

  • 上图并没有画出每一步,请自行脑补
  • 由上图可见,i 始终指向 0,j 的作用就是寻找非 0 数
  • 一旦找到就进行交换

思考过程:

本菜鸟一开始交换两数还用的是最传统的 temp 三步法,结果被 swap 函数一把子秒了!对于双指针,既然 i 和 j 必须是一前一后地移动(毕竟自己没有和自己交换的必要),那为什么初始化的时候要令 j 等于 i 呢?这是因为 nums 的长度可能为 1,你初始化 j = 1 就越界了。

class Solution {
public:void moveZeroes(vector<int>& nums) {int i = 0, j = 0;while (j < nums.size()) {if (nums[j] != 0) {swap(nums[i], nums[j]);++i;}++j;}}
};

每完成一次交换,i 就要向右移动一格,毕竟之前的序列已经处理好了。无论交不交换,j 都要向右移动一格。若交换,则代表 j 当前指向 0;若没交换,则还是代表 j 当前指向 0 。而 j 是用来寻找非 0 数的,因此必须向右移动。

2  11. 盛最多水的容器

解题思路:

  1. 两个指针一头一尾遍历数组
  2. 若左侧更低则左边的指针移动,若右侧更低则右边的指针移动
  3. 每次移动完就计算新的面积,并和历史最大面积做比较

思路说明图:

这里我们的移动标准是 “哪侧的边矮,我们就移动哪侧”。为什么这样做呢?难道不会遗漏更好的组合吗?举个例子,对于初始组合 1 和 9,面积的高度等于 1 这个矮边,又因为 9 离 1 最远,所以面积的宽度已经取到了极值,这就是针对 1 这个矮边的最大面积了!我们再怎么移动右侧的边也不能使面积增大。

同样地,当左侧的边移动到 2 时,9 成了矮边。在保证 9 是矮边的条件下,2 又是离 9 最远的,所以面积的宽度已经取到了极值,这就是针对 9 这个矮边的最大面积了!我们再怎么移动左侧的边也不能使面积增大。

class Solution {
public:int maxArea(vector<int>& height) {int i = 0, j = height.size() - 1;int area = min(height[i], height[j]) * (j-i);while (i != j) {if (height[i] < height[j]) {++i;} else if (height[i] > height[j]) {--j;} else {++i;}area = max(area, min(height[i], height[j]) * (j-i));}return area;}
};

3  15. 三数之和

解题思路:

  1. 为数组排序
  2. 进行三层循环,每层循环针对三数中的一个
  3. 第二层和第三层体现了双指针,一个从头开始,一个从尾开始

思路说明图:

1)双指针

传统的三层循环如 method1 所示,即 i、j 和 k 都是从左至右遍历数组。但是因为排序后的数字是按从小到大的顺序排序的,并且要求 nums[i] + nums[j] + nums[k] == 0 。又由于 i 和 j 是从左至右遍历的,nums[i] + nums[j] 会变得越来越大,因此 nums[k] 应该越来越小!这就要求 k 从右至左进行遍历,如 method2 所示。

2)避免重复

if (i > 0 && nums[i] == nums[i - 1]) continue;

这行代码是为了避免三元组出现重复。如上图所示,我们只看第一层循环。

当 i 等于第一个 -4 的时候,j 和 k 屁颠屁颠地给 i 找满足要求的组合,它们考虑的数字包含 {-4, -1, -1, 0, 1, 2, 2} 。当 i 等于第二个 -4 的时候,j 和 k 还是屁颠屁颠地给 i 找满足要求的组合,它们考虑的数字包含 {-1, -1, 0, 1, 2, 2} 。

这里少考虑了一个 -4 会影响结果吗?答案是并不会。只能说为第二个 -4 找的三元组可能比为第一个 -4 找的少一个罢了(如果数组里还有个 8 的话,就会少一个 {-4, -4, 8})但这并不影响啊,题目要求的就是不能重复!所以我们索性跳过第二个 -4,反正为它找的三元组已经存在了。

类似地,针对 j 也有这样的 if 语句。

if (j > i + 1 && nums[j] == nums[j - 1]) continue;

3)第三层循环

按理说,第三层循环也拿 for 做不就好了吗,条件为 j < k,只要 --k 就好了呀,但会超时……

还是那个思路 “能少循环就少循环”。

while (j < k && nums[i] + nums[j] + nums[k] > 0) --k;

这里有两个条件。一个是 j 不能遇上 k,它避免了 nums[k] 和 nums[i]、nums[j] 取到同一个位置的值;另一个是 nums[i] + nums[j] + nums[k] > 0,它避免了 nums[i] + nums[j] + nums[k] <= 0 以后,k 还在一个劲儿地往左移。

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 k = nums.size() - 1;// 第二层循环for (int j = i + 1; j < nums.size(); ++j) {if (j > i + 1 && nums[j] == nums[j - 1]) continue;// 第三层循环while (j < k && nums[i] + nums[j] + nums[k] > 0) --k;// 处理循环结果if (j == k) break;if (nums[i] + nums[j] + nums[k] == 0) {result.push_back({nums[i], nums[j], nums[k]});}}}return result;}
};

这道题最离谱的是把 int k = nums.size() - 1; 改写到第二层循环里也会超时啊!?

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单的天天酷跑小游戏实现

初级函数实现人物,背景,小乌龟的移动 #include <graphics.h> #include <iostream> #include <Windows.h> #include "tools.h" #include <mmsystem.h> #include <conio.h> #include <time.h>//时间头文件 #include <cstdlib&g…

关于 mysql数据库应用程序登录卡顿无响应崩溃 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135682663 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

FPGA 多路分频器实验

1 概述 在 FPGA 中&#xff0c;时钟分频是经常用到的。本节课讲解 2 分频、3 分频、4 分频和 8 分频的 Verilog 实现并且学习 generate 语法功能的应。 2 程序设计思路 1&#xff09;整数倍分频&#xff0c;为 2、4、8&#xff0c;这种 2^n 次方倍数倍数关系的…

postman后端测试时invalid token报错+token失效报错解决方案

报错信息1{“msg”:“invalid token”,“code”:401} 没有添加postman的token信息 报错信息2{“msg”: “token失效&#xff0c;请重新登录”,“code”: 401} 写了token但是token信息写的是错的,会提示token失效 解决方案如下 仅写完后端的查询,但是前端还没写的时候,可…

通信入门系列——信号的频谱分析

一、信号频谱 信号的频谱&#xff0c;指的是一段频率范围内的情况&#xff0c;信号的幅度和相位的情况。 以一个频率为1Hz的余弦电压信号进行说明&#xff0c;这个信号的傅里叶变换为X(ω)πδ(ω-2π)πδ(ω2π)&#xff0c;也就是所谓的频谱密度&#xff0c;单位为V/(rad/…

荒野大镖客提示emp.dll丢失修复方法

在玩荒野大镖客这款游戏时&#xff0c;有些玩家可能会遇到找不到emp.dll文件的问题。这个问题通常会导致游戏无法正常运行或出现错误提示。本文将介绍荒野大镖客找不到emp.dll丢失的解决方法&#xff0c;并解释emp.dll是什么以及导致其丢失的原因。 什么是emp.dll&#xff1f; …

linux云服务器 如何将数据盘挂载到系统盘上面?

先认识认识下面几个常用命令 lsblk 命令&#xff1a;查看设备列表&#xff0c;也就是能看到系统盘和数据盘一般为&#xff1a;vda&#xff08;系统盘&#xff09;、vdb&#xff08;数据盘&#xff09;等等 lsblk"ls" 是 "list" 的缩写&#xff1a; lsblk…

HBase学习六:LSM树算法

1、简介 HBase是基于LSM树架构实现的,天生适合写多读少的应用场景。 LSM树本质上和B+树一样,是一种磁盘数据的索引结构。但和B+树不同的是,LSM树的索引对写入请求更友好。因为无论是何种写入请求,LSM树都会将写入操作处理为一次顺序写,而HDFS擅长的正是顺序写(且HDFS不…

[STM32F407ZET6] GPIO

GPIO模式 F4的GPIO功能比F1的功能更多一些, 但是整体框架一样. F4的输出配置和F1的不同, F4的配置后, 施密特触发器将会开启, 还会对输入寄存器进行采样读取. F1的配置后, 推挽输出将会关闭施密特触发器, 开漏模式读取会读输入寄存器, 推挽模式会读取输出寄存器的值. 输出(全…

软件测试|使用matplotlib绘制箱型图

简介 绘制箱型图&#xff08;Box Plot&#xff09;是一种常用于可视化数据分布的方法&#xff0c;它可以显示数据的中位数、四分位数、异常值等统计信息。Matplotlib 是一个强大的 Python 数据可视化库&#xff0c;可以轻松绘制箱型图。在本文中&#xff0c;我们将介绍如何使用…

KNN算法原理及应用

理解KNN 算法原理 KNN是监督学习分类算法&#xff0c;主要解决现实生活中分类问题。 根据目标的不同将监督学习任务分为了分类学习及回归预测问题。 监督学习任务的基本流程和架构&#xff1a; &#xff08;1&#xff09;首先准备数据&#xff0c;可以是视频、音频、文本、…

聚类模型评估指标

聚类模型评估指标-轮廓系数 计算样本i到同簇其它样本到平均距离ai&#xff0c;ai越小&#xff0c;说明样本i越应该被聚类到该簇&#xff08;将ai称为样本i到簇内不相似度&#xff09;&#xff1b;计算样本i到其它某簇Cj的所有样本的平均距离bij&#xff0c;称为样本i与簇Cj的…