算法-双指针专题

文章目录

  • 概念
    • 应用场景:
    • 常见问题类型:
  • 对向指针模型
  • 同向指针模型
  • 多序列模型

概念

双指针法是一种常用的算法思想,通常用于解决数组或链表相关的问题。该方法的核心思想是使用两个指针在数据结构中按照一定的规则移动,以解决问题或寻找特定的解。这两个指针可以按照不同的方式移动:一起移动、相向移动、同向移动等。下面我将详细介绍双指针思想的应用场景以及常见的问题类型。

应用场景:

  1. 数组或链表中的查找:双指针可以用来在有序或无序数组中查找满足某种条件的元素或子数组。例如,可以使用双指针找到数组中的两个数之和等于目标值的组合,或者找到链表中倒数第 k 个节点。

  2. 数组或链表中的倒序遍历:当需要在数组或链表中倒序遍历时,双指针可以是一个有效的选择。例如,需要将链表反转或者数组中的元素按某种条件倒序排列。

  3. 滑动窗口:在数组或字符串中,有一类问题需要找出满足一定条件的子串,而且这个子串是连续的。例如,在一个字符串中找到最短的包含目标字符的子串,或者找到子数组的最大和不超过某个值。这种问题通常可以通过双指针来解决,其中一个指针用于扩展窗口,另一个指针用于收缩窗口。

  4. 链表中的环检测与环的起点:使用快慢指针可以检测链表中是否存在环,并且可以找到环的起点。

常见问题类型:

  1. 在数组中找到两个数之和等于目标值。

  2. 反转链表。

  3. 将两个有序数组合并为一个有序数组。

  4. 在有序数组或链表中删除重复元素。

  5. 在数组中找到可以盛水最多的容器。

  6. 检测链表中是否存在环。

  7. 找到字符串中包含目标子串的最短窗口。

  8. 找到字符串中最长的无重复字符子串。

双指针法是解决数组、链表等数据结构中一类特定问题的常用技巧。它通常能够以较低的时间复杂度解决问题,并且易于实现。通过灵活地控制指针的移动,可以解决各种不同类型的问题,包括查找、遍历、合并、移除等操作。

下面我们总结几种常用模型,并配上例题来讲解。

对向指针模型

两个指针,初始一个在左、一个在右,左指针向右移动,右指针向左移动,直到相撞停止。

适用场景:二分查找、反转数组、回文判定。

在这里插入图片描述
在这里插入图片描述

对于这个问题,我们进行遍历的时候就可以用两个指针,一个从前开始一个从后开始,那么很明显,我们指针移动有三种情况

  1. 找到了等于k等情况,此时low指针向后走,high指针向前
  2. 当前算的值比k大,那么让high向前走
  3. 当前算的值比k小,那么low指针应该向后走
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n,k,a[N];

int main(){
	cin >> n >> k;
	for(int i = 0;i < n;i ++) cin >> a[i];
	int low = 0,high = n-1,sum = 0;
	while(low < high){
		if(a[low]+a[high] == k){
			sum++;
			high = high - 1;
			low = low + 1;
		}else if(a[low]+a[high] > k){
			high = high - 1;
		}else{
			low = low + 1;
		}
	}
	cout << sum;
	return 0;
}

同向指针模型

两个指针,初始在同一位置,然后向相同方向移动,一个移动速度快,一个移动速度慢。

适用场景:查找链表中间节点、链表是否包含环、原地修改数组。

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

链表中结点的数目为 sz

1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

那么对于我们这个问题,我们可以用两个指针去维护,一个慢指针,一个快指针,快慢指针始终保持n这个间距,那么快指针走到底的时候,慢指针指向的位置就是倒数第n个结点的位置

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
     ListNode* dummy = new ListNode(0, head);
    ListNode* slow = dummy;
    ListNode* fast = dummy;

    for (int i = 0; i < n + 1; i++) {
        fast = fast->next;
    }

    while (fast != nullptr) {
        slow = slow->next;
        fast = fast->next;
    }

    slow->next = slow->next->next;
    return dummy->next;
    }
};

多序列模型

我们上面介绍的都是仅限于单序列问题,下面我们介绍几种多个序列应用双指针的模型。

在这里插入图片描述
这种就是最基本的双序列合并问题,我们可以定义两个指针,分别指向序列1和序列2,然后开始遍历,如果序列1的data比序列2更小,那我们把序列1加入我们的新序列3中,然后让序列1的指针向前移动,如果我们遇到空的情况,那就直接让新序列接上另一段序列。

我这里用的是链表去实现,大家可以自己用数组去实现一下,数组会更好实现。

#include<bits/stdc++.h>
using namespace std;

typedef struct node{
	int data;
	node *next;
}LNode,*LinkList;

int main(){
	int n,m,tmp;
	cin >> n >> m;
	LinkList l1 = (LinkList)malloc(sizeof(LNode));
	LinkList l2 = (LinkList)malloc(sizeof(LNode));
	LinkList l3 = (LinkList)malloc(sizeof(LNode));
	l1->next = NULL;
	l2->next = NULL;
	l3->next = NULL;
	LinkList r1 = l1,r2 = l2,r3 = l3;
	while(n--){
		cin >> tmp;
		LinkList tmpNode = (LinkList)malloc(sizeof(LNode));
		tmpNode->data = tmp;
		r1->next = tmpNode;
		r1 = r1->next;
	}
	r1->next = NULL;
	while(m--){
		cin >> tmp;
		LinkList tmpNode = (LinkList)malloc(sizeof(LNode));
		tmpNode->data = tmp;
		r2->next = tmpNode;
		r2 = r2->next;
	}
	r2->next = NULL;
	LinkList q = l1->next,p = l2->next;
	while(q&&p){
		if(p->data >= q->data){
			r3->next = q;
			q = q->next;
			r3 = r3->next;
		}else{
			r3->next = p;
			p = p->next;
			r3 = r3->next;
		}
	}
	r3->next = (p?p:q);
	LinkList s = l3->next;
	while(s){
		cout << s->data;
		s = s->next;
		if(s) cout << " ";
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1篇《Nature》、2篇《Cell》,重磅揭示CyTOF技术在类自身免疫病中的应用趋势

自身免疫病的研究如火如荼&#xff0c;目前已有近百种自身免疫疾病被发现&#xff0c;然而近百种自身免疫病的发病机制和症状皆有不同&#xff0c;探究自身免疫病的机制是推进疾病研究的重要任务。当前自身免疫病研究手段主要是通过检测自身抗体的异常表达或细胞因子的紊乱来阐…

Spring Data Envers 数据审计实战

随着各行各业信息化发展&#xff0c;决策者们越来越意识到数据版本追踪的重要性&#xff0c;尤其是上市公司&#xff0c;数据对于他们尤为重要。考虑到研发成本&#xff0c;对重要表单数据支持页面级的修改历史查看、对所有业务数据支持DB级的版本查看是一个不错的选择。 对于…

如何在Linux部署Yearning并结合cpolar实现公网访问内网管理界面

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

回望·前行 | 经纬恒润年度大事记回顾

经纬恒润年度大事记重磅发布&#xff01;

通过无线打通两个路由器

通过无线打通两个路由器 上网向导无线连接 配置比较简单&#xff0c;有些路由器支持有些不支持&#xff0c;支持的大致就是下面的方法&#xff0c;不过不同型号面板不一样&#xff0c;这里主要学习方法&#xff0c;所以不做路由器型号介绍。 重要的事情说三遍&#xff1a;学习要…

5.0 ZooKeeper 数据模型 znode 结构详解

数据模型 在 zookeeper 中&#xff0c;可以说 zookeeper 中的所有存储的数据是由 znode 组成的&#xff0c;节点也称为 znode&#xff0c;并以 key/value 形式存储数据。 整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头。 进入 zookeeper 安装的 …

vue-3d-loader

vue-3d-loader - npm GitHub - king2088/vue-3d-loader: VueJS and threeJS 3d viewer 是对 vue-3d-model 的改进&#xff0c;降低Threejs使用难度 # 默认安装 "vue-3d-loader": "^1.3.4", 只支持vue2 npm i vue-3d-loader # vue3 需要安装2版本&#xf…

Vision Transformer(一):自注意力机制

1. 注意力机制 注意力本质上是模仿人的行为。这种行为可以描述为人在观察一些事物时&#xff0c;会对感兴趣的区域会产生更多的聚焦&#xff0c;而会选择性的忽视&#xff08;或者减少关注&#xff09;另一些区域。 举个简单的例子&#xff0c;一些对跑车感兴趣的人&#xff0…

【C语言】贪吃蛇 详解

该项目需要的技术要点 C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32API等。 由于篇幅限制 和 使知识模块化&#xff0c; 若想了解 使用到的 Win32API 的知识&#xff1a;请点击跳转&#xff1a;【Win32API】贪吃蛇会使用到的 Win32API 目录 1. 贪吃蛇游…

《数字孪生城市建设指引报告(2023年)》指引智慧城市行动方向

2023年12月27日&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;产业与规划研究所、中国互联网协会数字孪生技术应用工作委员会和苏州工业园区数字孪生创新坊联合发布《数字孪生城市建设指引报告&#xff08;2023年&#xff09;》。该报告提出了三大…

掌握CSS网格函数fit-content()的妙用

CSS网格布局是一种强大的布局系统&#xff0c;它提供了灵活的网格化设计能力。其中&#xff0c;fit-content()函数是一项重要的功能&#xff0c;它可以帮助我们在网格容器中自动调整网格项的尺寸。本文将详细讲解fit-content()函数的使用方法及其常见应用场景&#xff0c;助你掌…

探索PostgreSQL:从基础到实践(简单实例)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 下载前言一、PostgreSQL是什么&#xff1f;二、使用步骤1.引入库2.读入数据 总结 下载 点击下载提取码888999 前言 在当今的大数据时代&#xff0c;数据库作为信…

《Redis核心技术与实战》学习笔记1——基本架构:一个键值数据库包含什么?

基本架构&#xff1a;一个键值数据库包含什么&#xff1f; 文章目录 基本架构&#xff1a;一个键值数据库包含什么&#xff1f;可以存哪些数据&#xff1f;可以对数据做什么操作&#xff1f;采用什么访问模式&#xff1f;如何定位键值对的位置&#xff1f;不同操作的具体逻辑是…

【力扣】两数相加,模拟+递归

两数相加原题地址 方法一&#xff1a;模拟 注意到链表的方向是从低位到高位&#xff0c;而做“竖式相加”也是低位到高位。 1 2 3 4 5 ----------- 1 6 8 所以可以用同样的方法来模拟。如果不考虑进位&#xff0c;只需要取出对应位的2个数相加&#xff0c;再尾插到新的…

【flutter】报错 cmdline-tools component is missing

在flutterSDK目录下&#xff0c;双击flutter_console.bat&#xff0c;调出命令行。 输入flutter doctor&#xff0c;如果第三个诊断为[x]&#xff0c;报cmdline-tools component is missing错&#xff08;我这已经修改好了&#xff0c;所以是勾了&#xff09;&#xff0c;那就可…

爬虫(三)

1.JS逆向实战破解X-Bogus值 X-Bogus:以DFS开头&#xff0c;总长28位 答案是X-Bogus,因为会把负载里面所有的值打包生成X-Boogus 1.1 找X-Bogus加密位置&#xff08;请求堆栈&#xff09; 1.1.1 绝招加高级断点&#xff08;日志断点&#xff09; 日志断点看有没有X-B值 日志…

【wu-lazy-cloud-network】Java自动化内网穿透

项目介绍 wu-lazy-cloud-network 是一款基于&#xff08;wu-framework-parent&#xff09;孵化出的项目&#xff0c;内部使用Lazy ORM操作数据库&#xff0c;主要功能是网络穿透&#xff0c;对于没有公网IP的服务进行公网IP映射 使用环境JDK17 Spring Boot 3.0.2 功能 1.内网…

Hadoop-IDEA开发平台搭建

1.安装下载Hadoop文件 1&#xff09;hadoop-3.3.5 将下载的文件保存到英文路径下&#xff0c;名称一定要短。否则容易出问题&#xff1b; 2&#xff09;解压下载下来的文件&#xff0c;配置环境变量 3&#xff09;我的电脑-属性-高级设置-环境变量 4.详细配置文件如下&#…

神经网络的权重是什么?

请参考这个视频https://www.bilibili.com/video/BV18P4y1j7uH/?spm_id_from333.788&vd_source1a3cc412e515de9bdf104d2101ecc26a左边是拟合的函数&#xff0c;右边是均方和误差&#xff0c;也就是把左边的拟合函数隐射到了右边&#xff0c;右边是真实值与预测值之间的均方…

[Linux] 网络编程套接字

目录 预备知识 网络字节序 网络字节序和主机字节序转换的库函数 socket编程接口 socket常见API sockaddr结构 套接字的种类 预备知识 1.在IP数据包头部中&#xff0c;有两个IP地址&#xff0c;分别叫做源IP地址和目的IP地址。 2.端口号&#xff1a;是传输层协议的内容…