当前位置: 首页 > 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…...

SOLID - 依赖倒置原则(Dependency Inversion Principle)

SOLID - 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff09; 定义 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是面向对象设计中的五大基本原则之一&#xff0c;通常缩写为SOLID中的D。DIP由Robert C. Martin提出&…...

【.NET 8 实战--孢子记账--从单体到微服务】--需求拆分与规划

在上一篇文章中我们收集了需求&#xff0c;并对需求进行了简单的分析和规划&#xff0c;但是对于开发人员来说&#xff0c;上一篇文章的需求还不够详细&#xff0c;并且没有形成计划。因此本篇文章将带领大家来拆分需求并规划开发里程碑。 一、详细需求列表 项目组进行了多次…...

在macOS的多任务处理环境中,如何平衡应用的性能与用户体验?这是否是一个复杂的优化问题?如何优化用户体验|多任务处理|用户体验|应用设计

目录 一 多任务处理与应用性能 1. macOS中的多任务处理机制 2. 性能优化的基本策略 二 用户体验的关键要素 1. 响应速度 2. 界面友好性 3. 功能的直观性 三 平衡性能与用户体验的策略 1. 资源管理 2. 优化数据加载 3. 使用合适的线程模型 4. 实时监测和调整 四 使…...

Vscode配置CC++编程环境的使用体验优化和补充说明

文章目录 快速编译运行&#x1f47a;code runner插件方案Code Runner Configuration 直接配置 相关指令和快捷键默认task配置和取消默认 配置文件补充介绍(可选 推荐阅读)&#x1f60a;使用vscode预置变量和环境变量环境变量的使用使用环境变量的好处环境变量可能引起的问题 检…...

十个方法杜绝CAD图纸泄密风险!2024年图纸防泄密指南!「必看」

随着信息技术的发展&#xff0c;CAD图纸的应用日益普遍&#xff0c;然而随之而来的图纸泄密风险也愈加严重。企业在提升效率的同时&#xff0c;更需重视信息安全。为此&#xff0c;本文将介绍十个有效的方法&#xff0c;帮助企业杜绝CAD图纸泄密风险&#xff0c;保障商业机密。…...

技术干货|HyperMesh CFD功能详解:虚拟风洞 Part 1

虚拟风洞VWT 从2023版本开始&#xff0c;虚拟风洞VWT&#xff08;Virtual Wind Tunnel&#xff09;模块合并到HyperMesh CFD中。 用户在VWT模块中完成LBM求解器ultraFluidX的前处理设置&#xff0c;导出参数文件XML和模型文件STL&#xff0c;并在GPU服务器上提交计算。 VWT目前…...

022集——统计多条线的总长度(CAD—C#二次开发入门)

如下图所示&#xff0c;选择多条线并统计长度&#xff1a; c#中不包含直接获取curve曲线长度 属性&#xff0c;需用如下方法&#xff1a;curve.GetDistanceAtParameter(item.EndParam) 附部分代码如下&#xff1a; using Autodesk.AutoCAD.ApplicationServices; using Autode…...

大模型重要技术系列三:高效推理

接上一篇高效训练&#xff0c;这一篇汇总下高效推理的方法。高效推理的两个主要优化目标是低延迟&#xff08;快速得到推理结果&#xff09;和高吞吐量&#xff08;能同时处理很多请求&#xff09;&#xff0c;同时还要尽可能地少用资源&#xff08;算力、存储、网络带宽&#…...

Android 刘海屏适配指南

如果您不希望您的内容与刘海区域重叠&#xff0c; 以确保您的内容不会与状态栏及 导航栏。如果您要呈现在刘海区域中&#xff0c;请使用 WindowInsetsCompat.getDisplayCutout() 检索 DisplayCutout 对象 包含每个刘海屏的安全边衬区和边界框。借助这些 API 您需要检查视频内容…...

微信小程序服务通知

项目中用到了小程序的服务消息通知&#xff0c;通知订单状态信息&#xff0c;下边就是整理的一下代码&#xff0c;放到项目中&#xff0c;把项目的小程序appid和小程序的secret写进去&#xff0c;直接运行即可 提前申请好小程序服务信息通知短信模板&#xff0c;代码需要用到模…...