当前位置: 首页 > news >正文

算法练习——双指针

前言:大佬写博客给别人看,菜鸟写博客给自己看,我是菜鸟。

学前须知(对自己):这里的指针不一定指地址!也可能是数组下标。

1:移动零(双指针)

题目要求:

解题思路:

这道题的思路与先前快速排序中的lumoto法及其类似,只不过先前是通过双指针在数组中寻找基准值,这里是通过双指针将大于0的数排列在前。可以看到思路是完全相似的,不过是要求不一样。

在这里我们定义两个指针:

cur:当前指针的位置,初始值定义为0;

dest:需要替换数据的位置,初始值定义为-1;

让cur去遍历整个数组。

循环内,去寻找数组中不为0的数字

若满足条件(不为零),让dest++,随后与cur位置的数据进行交换。

若不满足条件,则让cur++,以此循环,直至cur遍历完整个数组。

代码实现:

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

2:复写零(双指针)

题目要求:

解题思路:

题目要求我们在原数组上进行修改,这说明一定涉及①:数据的交换②:数据向后平移。

此题要求复写零,那么不可能是数据的交换,则一定考虑数据的平移。但是仅仅从左往右遍历数组,然后平移数据,会丢失数组中原有的数据,因此需要从后往前遍历,以此平移数据同时添0

既然同样是双指针的思路,那么如何正确找到两个指针的起始位置呢?

同样以 cur 和 dest 来命名,他们的初始值分别为 0 ,-1;

当 cur 当前数据非零时,dest++;

当 cur 当前数据为零时,dest+=2;

然后判断当前 dest 是否已经超过或者等于数组长度,若满足则停止循环,不满足则cur++;

如果仅仅是题目中的案例,上述过程已经能正确找到 cur 和dest的位置,但有一种情况例外,那就是:dest 超出了数组,这种情况需要单独考虑。

已如下数组为例:[8,4,5,0,0,0,0,7];

如果按照上述过程,最终 cur 和 dest 的位置会来到如图所示处。

此时 dest 已经越过数组,因此我们所要作的,就是:将 dest -1 的位置置为 0,

同时将 dest -= 2, cur--即可。

注:思考为什么将dest -1 置为 0?

答:之所以为产生越界,是因为 cur 位置当前数据为0,因此 dest 多加了一次,才会导致越界,说明 dest 与 dest +1 的位置原本都应该为 0,但是数组越界了,所以只有dest位置的数据为0,因此需要将数组末尾置为0。

简单来说,针对越界这种特殊情况,我们手动进行了一次操作,即在数组末尾插入了零。

代码实现:

void duplicateZeros(vector<int>& arr) {int cur = 0, dest = -1;size_t n = arr.size() - 1;while(cur <= n ){if(arr[cur] == 0){dest += 2;}else{dest++;}if(dest >= n){break;}cur++;}if(dest > n){arr[dest-1] = 0;dest -=2;cur--;}while(cur >= 0){if(arr[cur] != 0){arr[dest--] = arr[cur--];}else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}

3:快乐数(快慢指针)

题目要求:

解题思路:

开始讲解思路前,需要知道一点:快乐数与先前链表中通过快慢指针确定链表是否为环形链表类似。一个数。经过多次运算后,始终会等于先前运算过的一个数,然后依次往复循环。

这里我们定义:

Num_Square()  函数:计算每位平方数的和

slow:调用一次上述函数

fast:调用两次上述函数

代码实现:

 int Num_Square(int n){int sum = 0;while(n){sum += pow(n%10,2);n /= 10;}return sum;}bool isHappy(int n) {int slow = n;int fast = Num_Square(n);while(slow != fast){slow = Num_Square(slow);fast = Num_Square((Num_Square(fast)));}if(slow == 1){return true;}else{return false;}}

4:装最多的水(双指针+单调性)

题目要求:

解题思路:

遇事不决,暴力思路,那显然是不可能的,因为会超时间复杂度。单纯使用前面的双指针算法似乎也不可行。

问:那这里该如何解决,才能优化时间复杂度呢?

答:这里不仅仅需要双指针,还需要结合单调性去考虑问题。

我们先定义两个指针:

left:初始值为0,指向数组最左端。

right:初始值为 n-1,n为数组元素个数,指向数组最右端。

现在想想水的容积是怎么算的?

容积 = 两边最短的高度 × 长度(right - left);

结合单调性,不难想到,如果此时 right--,left不变,那么任何数乘以 1 , 都会小于原来的容积(因为高度不变,长度减小),因此我们只需记录目前的最大值,然后left++,这样就减少了遍历次数,提升了效率。

此时 left = 1,right = n -1,同样结合上述单调性来看,如果left++,right 不变,那么任何数乘以 7,都会小于原来数(同样是因为高度不变,长度减小),因此这次我们需要将 right--,left不变,这样就减少了遍历次数,提升了效率。

总结:通过双指针+单调性去考虑这个问题

起始时:left = 0,right = n-1;

容积 = min(arr[left],arr[right]) × (right - left);

高度固定时,容积与长度为反比,记录此时容积大小,并改变较小的高度(left就++,right就--)

最终比较记录的容积值即可。

代码实现:

int maxArea(vector<int>& height) {size_t left = 0;size_t right = height.size()-1;int Max = 0;int ret = 0;while(left < right){Max = min(height[left],height[right]) * (right - left);ret = max(ret,Max);if(height[left] > height[right]){right--;}else{left++;}}return ret;}

5:有效三角形个数(双指针+单调性)

题目要求:

解题思路:

通常我们通过判断三次两边之和小于第三边来确定三个数是否能够构成三角形。

问:怎么做?才能够减少判定次数,同时又能确定可以构成三角形?

答:用较小的两个边的和与最大的边进行比较,这样只需判断一次。

问:那如何找最大值呢?

答:遍历数组去找肯定是不可取的,那么就会想到,使用库函数的排序,这样最大值一定在数组末尾。

在有了上述的考虑后,本题同样是双指针+单调性去思考问题,无非就是条件不同。

以下列数组为例分析:

图一:

 arr[left] + arr[right] < max  不构成三角形,那么比 arr[right] 小的数都不构成三角形,因此不用遍历,left++

图二:

 arr[left] + arr[right] > max 构成三角形,那么此时只要比 arr[left] 大的数,都能够构成三角形,因此无需遍历,直接记录一共可以构成三角行的个数 n = right - left。记录完后,right--

图三:

此时,又回到了图一的情况,不多赘述,left++。

直至不满足 left < right ,此时需要更新 max,left 和 right 重新循环上述过程,知道 max = arr[2];

代码实现: 

int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());size_t n = nums.size() -1;int total = 0;while(n >=2){int left = 0;int right = n-1;while(left < right){if(nums[left] + nums[right] <= nums[n]){left++;}else{total += right - left;right--;}}n--;}return total;}

6:和为 s 的两个数字(双指针+单调性)

题目要求:

解题思路:

几乎与5是一样的,只不过5中是与数组中的元素比,而这里是与给定的数比,因此更简单。

大致思路:

考虑双指针(left,right),因为数组是有序数组,从单调性考虑。

若 arr[left] + arr[right] > target 说明太大了,right--

若 arr[left] + arr[right] < target 说明太小了,left++

代码实现:

vector<int> twoSum(vector<int>& price, int target) {int left = 0;int 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 {-1,-1};}

7:三数之和

题目要求:

解题思路:

仍就是通过双指针+单调性的思路去解决这道问题,但区别在于,我们不能够输出重复的答案,因此这里还多了一个判重的过程。

如图定义来进行模拟运算:

当 arr[left] + arr[right] < arr[min] 时,left++;

当 arr[left] + arr[right] >arr[min] 时,right--;

当 arr[left] + arr[right] = arr[min] 时,left++;如图所示

此时需将答案保存到临时容器中,并让left++,right--,同时需要去重,即:

当 arr[left] == arr[left-1]时,left++;

当 arr[right] == arr[right+1]时,right--;

同时需要注意越界,即在循环过程中,left 始终小于 right

当 left 大于 right时结束一轮循环时,此时 min++,也要去重,与left 与 right 的去重思路一致,同时注意越界,min 始终小于容器内数据个数

代码实现:

vector<vector<int>> threeSum(vector<int>& nums) {int min = 0;vector<vector<int>> tmp;sort(nums.begin(),nums.end());//让数组变得有序方便使用单调性while(min < nums.size() && nums[min]<= 0){int left = min+1;int right = nums.size() - 1;while(left < right){int sum = nums[left] + nums[right];if(sum + nums[min] > 0){right--;}else if(sum + nums[min] < 0) {left++;}else{tmp.push_back({nums[min],nums[left++],nums[right--]});while(left < right && nums[left] == nums[left - 1]){left++;}while(left < right && nums[right] == nums[right + 1]){right--;}}}min++;while(min < nums.size() && nums[min] == nums[min-1]){min++;}}return tmp;}

8:四数之和

题目要求:

解题思路:

四数之和与三数之和的思路极其类似,无非就是多了一个需要固定的数,以及多一层循环,本质没有太大区别。

如图所示,固定 min 和 min1 去移动 left 和 right

当 arr[min] + arr[min1] + arr[left] + arr[right] < target时,left++

当 arr[min] + arr[min1] + arr[left] + arr[right] > target时,right--

当 arr[min] + arr[min1] + arr[left] + arr[right] = target时,

将当前  arr[min] ,arr[min1] , arr[left] , arr[right] 插入临时容器中

left++,right--,再判重,并注意越界

当最内层 left 和 right 循环结束时,min1++,并判重注意越界,开始下一轮循环

当 min1 等于倒数第三个下标时,第二层循环的首轮结束,min++,并判重,以此往复,直至循环结束。

代码实现:

vector<vector<int>> fourSum(vector<int>& nums, int target) {int min = 0;int n = nums.size()-1;vector<vector<int>> tmp;sort(nums.begin(),nums.end());while(min <= n-3){int min1 = min+1;while(min1 <= n-2){int left = min1+1;int right = nums.size() - 1;while(left < right){long sum = nums[left] + nums[right];long sum1 = nums[min] + nums[min1];if(sum + sum1 > target){right--;}else if(sum + sum1 < target) {left++;}else{tmp.push_back({nums[min],nums[min1],nums[left++],nums[right--]});while(left < right && nums[left] == nums[left - 1]){left++;}while(left < right && nums[right] == nums[right + 1]){right--;}}}min1++;while(min1 <= n-2 && nums[min1] == nums[min1-1]){min1++;}}min++;while(min <= n-3 && nums[min] == nums[min-1]){min++;}}return tmp;}

9:总结

双指针算法:

👉:这里的指针不是地址,也许是数组下标

👉:经常和单调性挂钩,有时候是根据数组长度判断单调(4),有时候是根据数组数据大小判断单调(5、6、7),根据数组数据判断单调可能需要将数组先排序,再做运算

相关文章:

算法练习——双指针

前言&#xff1a;大佬写博客给别人看&#xff0c;菜鸟写博客给自己看&#xff0c;我是菜鸟。 学前须知&#xff08;对自己&#xff09;&#xff1a;这里的指针不一定指地址&#xff01;也可能是数组下标。 1&#xff1a;移动零(双指针) 题目要求&#xff1a; 解题思路&#x…...

vue中el-table显示文本过长提示

1.el-table设置轻提示:show-overflow-tooltip“true“&#xff0c;改变轻提示宽度...

JS 字符串拼接并去重

1、includes 循环数组将某个字段拼接成新的字符串并去重&#xff08;数组里面包含的一个对象&#xff0c;或者其他都OK&#xff09; // 定义一个数组 let arr[.......] // 定义拼接的字符串 let a //循环数组将里面某个字段拼接在一起并去重 arr.forEach(item > {if(!a.in…...

opencv 图像预处理

图像预处理 ​ 在计算机视觉和图像处理领域&#xff0c;图像预处理是一个重要的步骤&#xff0c;它能够提高后续处理&#xff08;如特征提取、目标检测等&#xff09;的准确性和效率。OpenCV 提供了许多图像预处理的函数和方法&#xff0c;以下是一些常见的图像预处理操作&…...

SAP B1 功能模块字段介绍 - 价格清单(下)

目录 背景 五、业务伙伴的特殊价格 1. 单据逻辑功能 2. 部分字段解释 3. 操作流程 3.1 时间相关 3.2 数量相关 4. 实例 六、复制特殊价格到选择标准 1. 单据逻辑功能 2. 部分字段解释 七、全局更新特殊价格 ​编辑 1. 单据逻辑功能 2. 部分字段解释 八、价格更…...

传智杯 第六届-复赛-D

题目描述&#xff1a; 小红定义两个字符串同构&#xff0c;当且仅当对于i∈[1,n],b[i]−a[i]i∈[1,n],b[i]-a[i]i∈[1,n],b[i]−a[i]是定值。例如&#xff0c;"bacd"和"edfg"是同构的。 现在小红拿到了一个长度为n的字符串a&#xff0c;她想知道&a…...

Java - 数组实现大顶堆

题目描述 实现思路 要实现一个堆&#xff0c;我们首先要了解堆的概念。 堆是一种完全二叉树&#xff0c;分为大顶堆和小顶堆。 大顶堆&#xff1a;每个节点的值都大于或等于其子节点的值。 小顶堆&#xff1a;每个节点的值都小于或等于其子节点的值。 完全二叉树&#xff…...

ifuse挂载后,在python代码中访问iOS沙盒目录获取app日志

上一次使用pymobiledevice3&#xff0c;在python代码中访问app的沙盒目录并分析业务日志&#xff0c;在使用过程中发现&#xff0c;在获取app日志的时候速度很慢&#xff0c;执行时间很长&#xff0c;需要30-61秒&#xff0c;所以这次尝试使用libimobiledevic和ifuse&#xff0…...

Windows WSL环境下安装 pytorch +ROCM 支持AMD显卡

官方文档&#xff1a;Install PyTorch for ROCm — Use ROCm on Radeon GPUs 一、操作系统及驱动 windows 下安装WSL 环境( windows subsystem for Linux), 安装ubuntu 22.04环境。 安装 rocm 软件包&#xff1a; sudo apt update wget https://repo.radeon.com/amdgpu-insta…...

uniapp中skymap.html(8100端口)提示未登录的排查与解决方法

问题&#xff1a; 目前账号已经登录&#xff0c;uniapp的其他端口均可以访问到数据&#xff0c;唯独skymap.html中的8100会提示未登录。&#xff08;8100是后端网关gateway端口&#xff09; 分析&#xff1a; 在 skymap.html 中遇到未登录提示的问题&#xff0c;通常是由于该…...

训练模型时梯度出现NAN或者INF(禁用amp的不同level)

判断参数梯度位nan或inf的代码&#xff1a; for name, param in model.named_parameters():if param.grad is not None:if torch.isnan(param.grad).any() or torch.isinf(param.grad).any():print(f"grad layer [{name}] is NaN or Inf") 首先来说可能得原因&…...

Maven核心概念

一、项目对象模型&#xff08;POM&#xff09; 1. 定义 POM&#xff08;Project Object Model&#xff09;是 Maven 项目的核心配置文件&#xff0c;它以 XML 格式描述了项目的基本信息、项目依赖、构建配置等。可以说&#xff0c;POM 是 Maven 理解和处理项目的基础。 2. 基…...

Sonatype Nexus 部署手册

文章目录 一、前言二、软件环境2.1 版本变更&#xff1a;2.1.1 变更存储的原因2.2.2 H2作为存储的注意点 三、资源配置四、开始部署4.1 部署jdk174.2 离线部署nexus4.2.1 下载4.2.2 部署1. 上传到服务器2. 解压3. 添加用户4. 修改启动参数5. 迁移sonatype-work &#xff0c;并授…...

TLV320AIC3104IRHBR 数据手册 一款低功耗立体声音频编解码器 立体声耳机放大器芯片麦克风

TLV320AIC3104 是一款低功耗立体声音频编解码器&#xff0c;具有立体声耳机放大器以及在单端或全差分配置下可编程的多个输入和输出。该器件包括基于寄存器的全面电源控制&#xff0c;可实现立体声 48kHz DAC 回放&#xff0c;在 3.3V 模拟电源电压下的功耗低至 14mW&#xff0…...

(8)结构体、共用体和枚举类型数据

1. 结构体、共用体的定义及区别,typedef 定义别名 结构体的定义 结构体是一种用户自定义的数据类型,它可以将不同类型的数据组合在一起。例如,定义一个表示学生信息的结构体: // 定义结构体类型 struct Student struct Student {char name[20];int age;float score; };共…...

Jedis操作和springboot整合redis

Jedis-springboot整合redis Jedis 引入jedis依赖 注意事项 测试相关数据类型 Key String List set hash zset 案例 spring boot整合redis 引入相关依赖 在application.properties中配置redis 配置 创建redis配置类 创建测试类 Jedis 引入jedis依赖 <depen…...

基于AI大模型的复杂扫描件PDF信息提取与规整

前言 场景大致是会上传一个几十页的扫描件PDF&#xff0c;让AI在当中找出我需要的字段&#xff0c;本文会隐去具体行业信息和具体的AI提示词内容&#xff0c;只分享技术相关内容&#xff0c;请见谅。 AI模型选择 针对我们行业的使用场景&#xff0c;我主要测试了GPT、Claude以…...

为什么https先非对称加密,然后对称加密?

HTTPS之所以先使用非对称加密&#xff0c;然后在对称加密&#xff0c;主要是基于两者在加密效率与安全性方面的特性考虑。 首先&#xff0c;非对称加密具有极高的安全性&#xff0c;因为它使用了公钥和私钥这一对密钥。公钥是公开的&#xff0c;任何人都可以使用它来加密数据&…...

【Coroutines】Full Understanding of Kotlinx.Corutines Framework

文章目录 What is CorutinesDifference between Corutine and ThreadFast UsageSuspend FunctionAdvanced Usage of CoroutineCoroutine EssentialsCoroutineContextCoroutineScopePredefined CoroutineScopePredefined DispatchersPredefined CoroutineStartJobCreate a Corou…...

Python面向对象,实现图片处理案例,支持:高斯模糊、Canny边缘检测、反转边缘图像、生成手绘效果、调亮度......等等

实验图片如下&#xff1a; 命名为img1.jpg, 放在项目下新建文件夹images下 项目构造如下&#xff1a; app.py源码如下 import cv2 import os from matplotlib import pyplot as plt import numpy as npclass ImageProcessor:def __init__(self, image_path):self.image cv…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库&#xff0c;用于数据验证和设置管理&#xff0c;通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发&#xff08;如 FastAPI&#xff09;、配置管理和数据解析&#xff0c;核心功能包括&#xff1a; 数据验证&#xff1a;通过…...