【双指针】

目录

1. LeetCode 283. 移动零

1.1 题目描述

1.2 题目思路 

1.3 实现代码

2. LeetCode 1089. 复写零

2.1 题目描述

2.2 题目思路 

2.3 实现代码

3. LeetCode 202. 快乐数

3.1 题目描述

3.2 题目思路

3.3 实现代码

4.  LeetCode 11. 盛水最多的容器

4.1 题目描述

4.2 题目思路

4.3 实现代码

5.  LeetCode 611. 有效三角形的个数

5.1 题目描述

5.2 题目思路

5.3 实现代码

6. LeetCode  LCR 179.查找总价格为目标值的两个商品

6.1 题目描述

6.2 题目思路

6.3 实现代码

7. LeetCode 15. 三数之和

7.1 题目描述

7.2 题目思路

7.3 实现代码

8. LeetCode 18. 四数之和

8.1 题目描述

8.2 题目思路

8.3 实现代码

9. 总结


1. LeetCode 283. 移动零

1.1 题目描述

题目链接:

LeetCode 283. 移动零icon-default.png?t=N7T8https://leetcode.cn/problems/move-zeroes/description/

1.2 题目思路 

题目要求,将数字零移动到数组最后,并不影响非零元素的相对位置,

  1. 我们可以利用两个指针dest和cur,cur用来遍历数组,dest用来指向非零元素的最后一个位置;
  2. 要保证[0, dest] 的元素是非零元素,[dest + 1, cur - 1] 的元素是全零,[cur , size() - 1]是未处理过的元素;
  3. 那我们只需看一下cur指向的元素是否是零,如果是零,就++cur,否则就交换dest和cur所在位置的值即可,然后再++cur,++dest。

1.3 实现代码

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

 


2. LeetCode 1089. 复写零

2.1 题目描述

题目链接:

LeetCode 1089. 复写零icon-default.png?t=N7T8https://leetcode.cn/problems/duplicate-zeros/ 

2.2 题目思路 

这题依然是定义两个指针,cur和dest,cur用来遍历数组,如果dest从前往后覆盖,肯定会把还未处理的值覆盖,所以dest只能从后往前覆盖,那我们肯定要找到最后一个要覆盖的值的位置,那如何找到呢:

  • 如果cur所在位置的值为零,那dest就往后走两步;
  • 否则dest往后走一步,每次走完都要判断dest所在的位置是否大于了size();
  • 然后再++cur;
  • 最后cur所在位置就是最后一个要复写的值。

这里需要有一个细节判断,当最后一个要复写的位置是零,并且如果dest向后走两步的话就超过了size(),这个时候应该:

  • --dest,然后让dest所在位置的值赋为0;
  • --cur。

OK,这样就可以从后往前开始复写了:

  • 如果cur所在位置的值不为零,就把这个位置的值赋给dest所在的位置;
  • 然后--cur,--dest,直到cur < 0。

2.3 实现代码

class Solution 
{
public:void duplicateZeros(vector<int>& arr) {int cur = 0, dest = -1;// 找到最后一个数while (cur <  arr.size()){if (arr[cur] != 0) { ++dest;}else{dest += 2;}if (dest >= arr.size() - 1) break;++cur;}// 判断边界if (dest == arr.size()){--dest;arr[dest] = 0;--dest;--cur;}// 从后往前复写while (cur >= 0){if (arr[cur]){arr[dest] = arr[cur];--dest; --cur;}else{arr[dest - 1] = arr[dest] = arr[cur];--cur; dest -= 2;}}}
};


3. LeetCode 202. 快乐数

3.1 题目描述

LeetCode 202. 快乐数icon-default.png?t=N7T8https://leetcode.cn/problems/happy-number/

3.2 题目思路

对于这道数字变换的题目,怎么能用到双指针呢?

其实这里的双指针,并不是实际意义上的指针,听我细细道来:

  • 这道题有一个点非常重要,题目说经过不停地变换,最后要么是无限循环,要么是变为1,其实变为1之后也是无限循环;
  • 那我么就可以运用这个规律来实现,定义一个slow,每次变换一次,fast,每次变换两次,那么最后fast和slow肯定相等,相等之后退出循环;
  • 最后如果slow和fast变成了1,那么就是快乐书,否则不是。

3.3 实现代码

class Solution 
{
public:int changeNum(int n){int sum = 0;while (n){sum += (n % 10) * (n % 10);n /= 10;}return sum;}bool isHappy(int n) {int slow = n, fast = changeNum(n);while (slow != fast){slow = changeNum(slow);fast = changeNum(fast);fast = changeNum(fast);}if (slow == 1) return true;return false;}
};


4.  LeetCode 11. 盛水最多的容器

4.1 题目描述

题目链接

11. 盛最多水的容器 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/container-with-most-water/description/

4.2 题目思路

方法一:

这题暴力解法思路很简单,就是把每个面积都求出来,取最小的就行,很明显时间复杂度是O(N^2),就不多讲了。

方法二:

  1. 定义两个指针left和right,left指向数组的开头位置,right指向数组的最后一个元素位置;
  2. 算出此时的面积square;
  3. 因为square = height * width,他的高度是由较小的那个决定的,如果left所在位置的值小,如果right向前走,height不会变,但是width肯定会变小,所以面积肯定是会变小的,此时就不用多余的计算面积了,直接让left--;
  4. 同理如果right所在位置的值小,那么如果让left++,那么height不会变,但是width肯定会变小,所以面积肯定会减小,这个时候--right即可。
  5. 直至left与right相遇。

那么这个算法的时间复杂度是left和right便利了一边数组,时间复杂度是O(N);

4.3 实现代码

class Solution 
{
public:int _Square(int width, int height){return width * height;}int maxArea(vector<int>& height) {int left = 0;int right = height.size() - 1;int Square = 0;while (left < right){int tmpSquare = _Square(right - left, min(height[right],height[left]));if (tmpSquare > Square) Square = tmpSquare;if (height[right] < height[left]) --right;else ++left;}return Square;}
};


5.  LeetCode 611. 有效三角形的个数

5.1 题目描述

题目链接

611. 有效三角形的个数 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/valid-triangle-number/

5.2 题目思路

方法一:

这题暴力解法就是把数组中取三个数的情况都列举出来,并判断是否能构成三角形,但是三角形要满足任意两边之和大于第三边,因此要判断三次,但是我们只要知道最大的边是哪一条,就可以判断一次,因此排序可以简化判断次数,但是这样的时间复杂度还是很高。

方法二:

既然数组必然要进行排序,那么数组肯定是有序了,既然有序了,我们可以思考一下更简单的方法。

  1. 既然要判断两个较小值的和是否大于最大的数,我们可以从后向前固定最大数;
  2. 然后定义left = 0,right为最大数位置的前一个位置;
  3. 判断两个位置的值是否大于最大的数,如果大于,那么说明[left, right - 1]区间内所有的值都能与 right 和 固定的最大数组成三角形,然后--right;
  4. 如果不大于,就让left++;
  5. 直至left与right相遇。

5.3 实现代码

class Solution 
{
public:int triangleNumber(vector<int>& nums) {int ret = 0;int n = nums.size();int loc = n - 1;sort(nums.begin(),nums.end());while (loc > 0){int left = 0, right = loc - 1;while (left < right){// 判断较小的两边之和是否大于最大边if (nums[left] + nums[right] > nums[loc]){ret += (right - left);--right;}else{++left;}}--loc;}return ret;}
};


6. LeetCode  LCR 179.查找总价格为目标值的两个商品

6.1 题目描述

题目链接

LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/description/

6.2 题目思路

这题暴力解法思路也很简单,就是计算所有的两数之和即可。很明显时间复杂度O(N^2)。

除此之外,我们可以利用排序+单调性来做:

  1. 首先对数组进行排序;
  2. 定义两个指针left和right分别指向第一个元素和最后一个元素所在的位置;
  3. 判断此时两个位置的和是否==target;
  4. 如果大于就--right,小于就++left,等于就返回。 

6.3 实现代码

class Solution 
{
public:vector<int> twoSum(vector<int>& price, int target) {sort(price.begin(),price.end());int left = 0, right = price.size() - 1;while (left < right){if (price[left] + price[right] > target) --right;else if (price[left] + price[right] < target) ++left;else return {price[left],price[right]};}return {0,0};}
};

 


7. LeetCode 15. 三数之和

7.1 题目描述

题目链接

15. 三数之和 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/3sum/description/

7.2 题目思路

这题与两数之和较为类似,与两数之和稍微不同的是,题⽬中要求找到所有「不重复」的三元组。那我们可以利⽤在两数之和
那⾥⽤的双指针思想,来对我们的暴力枚举做优化:

  1. 先排序;
  2. 然后固定⼀个数a :
  3. 在这个数后⾯的区间内,使⽤「双指针算法」快速找到两个数之和等于a即可。

但是要注意的是,这道题⾥⾯需要有「去重」操作

  1. 找到⼀个结果之后, left 和right指针要「跳过重复」的元素;
  2. 当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素

7.3 实现代码

class Solution 
{
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> vv;sort(nums.begin(),nums.end());for (int i = 0;i <= nums.size() - 3; ++i){if (nums[i] > 0){break;}int left = i + 1;int right = nums.size() - 1;while (left < right){if (nums[left] + nums[right] + nums[i] < 0) ++left;else if (nums[left] + nums[right] + nums[i] > 0) --right;else {vv.push_back({nums[left],nums[right],nums[i]});while (left < right && nums[left] == nums[left + 1]) {++left;}++left;while (left < right && nums[right] == nums[right - 1]) {--right;}--right;}}while (i < nums.size() - 3 && nums[i] == nums[i + 1]){++i;}}return vv;}
};

 


8. LeetCode 18. 四数之和

8.1 题目描述

题目链接

18. 四数之和 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/4sum/description/

8.2 题目思路

这题和三数之和也很类似,首先固定一个数,然后利用三数之和的思想。 

8.3 实现代码

class Solution 
{
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> vv;sort(nums.begin(), nums.end());if (nums.size() < 4) return vv;for (int i = 0;i <= nums.size() - 4; ++i){for (int j = i + 1; j <= nums.size() - 3; ++j){int left = j + 1, right = nums.size() - 1;while (left < right){if ((long long)nums[i] + nums[j] + nums[left] + nums[right] < target){++left;}else if ((long long)nums[i] + nums[j] + nums[left] + nums[right] > target){--right;}else{vv.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;}}while (j < nums.size() - 3 && nums[j] == nums[j + 1]){++j;}}while (i < nums.size() - 4 && nums[i] == nums[i + 1]){++i;}}return vv;}
};

 


9. 总结

总的来说,在双指针中,经常利用单调性来解决问题,例如这里的 盛最多水的容器、有效三角形的个数、包括两数之和、三数之和、四数之和,还需要多练习来锻炼思维,加油!

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

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

相关文章

Debian12 中重新安装MSSQL 并指定服务器、数据库、数据表字段的字符排序规则和默认语言等参数

在 Linux 上配置 SQL Server 设置 - SQL Server | Microsoft Learn 零、查看sql server 服务器支持的字符排序规则 SELECT Name from sys.fn_helpcollations() where name Like Chinese% go------ Chinese_PRC_CI_AI Chinese_PRC_CI_AI_WS Chinese_PRC_CI_AI_KS Chinese_PRC_…

FPGA中闪灯程序设计示例

在FPGA设计中&#xff0c;闪灯的作用主要是用于测试和验证设计的功能和性能。具体来说&#xff0c;闪灯可以作为一个可视化的指示器&#xff0c;通过控制LED灯的闪烁模式和频率&#xff0c;来显示FPGA的工作状态或调试信息。 例如&#xff0c;在设计过程中&#xff0c;可以编写…

政安晨:【Keras机器学习示例演绎】(二)—— 使用 DeepLabV3+ 进行多类语义分割

目录 简介 下载数据 创建 TensorFlow 数据集 构建 DeepLabV3 模型 训练 利用色图叠加进行推理 对验证图像进行推理 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益…

手动给docusaurus添加一个搜索

新版博客用docusaurus重构已经有些日子了&#xff0c;根据docusaurus的文档上也申请了Algolia,想一劳永逸的解决博客的搜索问题。但是流水有意&#xff0c;落花无情。 algolia总是不给我回复&#xff0c;我只能对着algolia的申请页面仰天长叹。 正常情况的申请 按照docusaur…

Gitlab: Python项目CI/CD实践

目录 1. 说明 2. 准备工作 2.1 服务器 2.2 开发机hosts文件 2.3 项目 3. 步骤过程 3.1 建仓Fastapi T1 3.2 开发机测试构建与推送 ​编辑 3.3 在工作站添加gitlab-runner 3.4 提交代码&#xff0c;查看Pipelines结果 3.5 观察部署情况 4. 参考 1. 说明 分别以一个…

【2024 SCI一区】 基于DCS-BiLSTM-Attention的多元回归预测(Matlab实现)

【2024 SCI一区】 基于DCS-BiLSTM-Attention的多元回归预测&#xff08;Matlab实现&#xff09; 目录 【2024 SCI一区】 基于DCS-BiLSTM-Attention的多元回归预测&#xff08;Matlab实现&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 差异创意搜索算法&…

C++ 静态成员函数(二)

一、访问静态成员变量 静态成员函数可以通过作用域运算符::来访问类的静态成员变量和静态成员函数 静态成员函数不属于任何特定的对象&#xff0c;而是属于整个类&#xff0c;可以通过类名直接调用&#xff0c;无需创建类的实例。静态成员函数不能访问类的非静态成员变量和非…

在 Linux 终端中创建目录

目录 ⛳️推荐 前言 在 Linux 中创建一个新目录 创建多个新目录 创建多个嵌套的子目录 测试你的知识 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 前言 在本系列的这一部…

Maven的dependencyManagement与dependencies区别

先说结论&#xff1a;Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。 在maven多模块项目的pom文件中&#xff0c;有的小伙伴会发现最外层的pom文件和里面的pom文件有个地方不一样 如下图 父pom 子pom 一般来说是在maven的最外父工程pom文件里&…

npm内部机制与核心原理

npm 的核心目标&#xff1a; Bring the best of open source to you, your team and your company. npm 最重要的任务是安装和维护开源库。 npm 安装机制与背后思想 npm 的安装机制非常值得探究。Ruby 的 Gem&#xff0c;Python的pip都是全局安装机制&#xff0c;但是npm的安装…

界面组件Telerik UI for WPF 2024 Q1新版亮点 - 全新DateRangePicker组件

Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序&#xff0c;同时还能快速构建企业级办公WPF应用程序。UI for WPF支持MVVM、触摸等&#xff0c;创建的应用程序可靠且结构良好&#xff0c;非常容易维护&#xff0c;其直观的API将无缝地集成Visual Studio…

如何正确查看容器的CPU使用率

进入容器中top&#xff0c;虽然看到的PID是容器的&#xff0c;但是%Cpu的统计信息却是宿主机的。 如图 原理 进程的cpu使用率是如何计算出来的&#xff1f; 每个进程的状态是放在文件里的&#xff0c;在/proc目录下&#xff0c;每个进程有自己pid命名的文件夹&#xff0c; …

.NET 爬虫从入门到入狱

目录 前言 1.&#x1f4a1;使用HttpClient爬取数据 2.&#x1f680;模拟User-Agent 3.&#x1f935;使用HTML解析库 3.&#x1f44c;前端Price显示 4.&#x1f331;运行实例 获取金价Au 5.&#x1f9fe;使用正则表达式解析 6.&#x1f4ab;获取BTC价格 7.✨获取CSDN热点…

4.15报错记录

打开文件时出错a bytes-like object is required,notNoneType 确保E:/data/stdata/st- images-1208-json|ST-WT-1.json是一个有效的标签文件。 今天用X-anylabling更改标签目录时出现这个报错 解决方案&#xff1a;图片文件夹中创建同名的一个文件夹把json文件放进去就可以打…

[Qt网络编程]之UDP通讯的简单编程实现

hello&#xff01;欢迎大家来到我的Qt学习系列之网络编程之UDP通讯的简单编程实现。希望这篇文章能对你有所帮助&#xff01;&#xff01;&#xff01; 本篇文章的相关知识请看我的上篇文章: http://t.csdnimg.cn/UKyeM 目录 UDP通讯 基于主窗口的实现 基于线程的实现 UDP通讯…

【YOLO系列PR、F1绘图】更改v5、v7、v8(附v8训练、验证方式),实现调用val.py或者test.py后生成pr.csv,然后再整合绘制到一张图上(使用matplotlib绘制)

目录 1. 前提 效果图2. 更改步骤2.1 得到PR_curve.csv和F1_curve.csv2.1.1 YOLOv7的更改2.1.1.1 得到PR_curve.csv2.2.1.2 得到F1_curve.csv 2.1.2 YOLOv5的更改&#xff08;v6.1版本&#xff09;2.1.3 YOLOv8的更改&#xff08;附训练、验证方式&#xff09; 2.2 绘制PR曲线 …

【创建型模式】抽象工厂模式

一、抽象工厂模式概述 抽象工厂模式定义&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 模式动机&#xff1a; 1.当系统提供的工厂生产的具体产品并不是一个简单的对象&#xff0c;而是多个位于不同产品等级结构、属于不同类型的…

41、二叉树-二叉树的层序遍历

思路&#xff1a; 层序遍历就是从左到右依次遍历。这个时候就可以使用队列的方式。例如先把头节点入队&#xff0c;然后遍历开始&#xff0c;首先计算队列长度&#xff0c;第一层&#xff0c;长度为了&#xff0c;遍历一次&#xff0c;依次出队&#xff0c;头结点出队&#xff…

Tomcat和Spring Boot配置https

生成测试证书 生成证书前&#xff0c;先验证本地是否正确配置jdk环境变量&#xff0c;如果jdk环境变量配置正确&#xff0c;在命令行程序输入生成证书的命令。 keytool -genkey -alias tomcat -keyalg RSA -keystore "F:\job\apache-tomcat-8.5.29\key\freeHttps.keysto…

微信小程序之图片上传并保存在服务器

先将图片上传到服务器&#xff0c;后端接口将保存好的图片地址返回给小程序&#xff0c;再将小程序中添加图像的图片的url替换为服务器中照片的存储地址&#xff08;使微信小程序中显示出上传的图片&#xff09;。 1、效果如下&#xff1a; 点击图像后选择图像&#xff1a; 结…