算法基础--双指针

       前面已经写了两篇关于算法方面的文章,这几天想了下,决定把这个算法整理成一个系列,除了是帮助自己巩固算法知识外,还能够把自己总结的每种算法的套路保存下来并分享给大家,这样以后即使是哪天想要重拾起来,也是能够根据这些算法套路快速重拾。

        我想了下,算法这块主要分为五大块,分别是双指针、栈(单调栈)、深度优先搜索(DFS)、广度优先搜索(BFS)、动态规划。今天就从双指针开始,从双指针算法概述、套路模板,以及根据这个模板,进行几道算法题的讲解,从简单到难,让小白也能由浅入深了解这个算法。

        双指针,是一种通过设置两个指针不断进行单向移动来解决问题的算法思想。一般包含两种形式:一、两个指针指向同一个序列。二、两个指针分别指向不同的序列。指向同一序列的比较常见,代表有快慢指针首尾指针固定间距指针等。指向不同序列的双指针代表有归并排序这种,需要合并时用双指针或者多指针。

        说得那么概念,可能大家反而没什么感觉,不就是两个指针,根据一定的条件触发两个指针的移动,然后把满足一定条件的结果作为最终结果嘛。但是,下面,来点干货,套路模板来了,不管什么样的算法题,只要是双指针的题目,记住下面这个套路模板,然后稍微调整下边界值,就可以直接往上套了,以不变应万变:

public Type twoPoints() {
        int left;
        int right;
        Type result
        while (满足继续循环条件) {
            if (满足左指针移动) {
                left++;
				if(满足更新result条件) 更新result;
            } else {
                right++/right--;
				if(满足更新result条件呢) 更新result;
            }
        }
        return result;
    }

那么好,看到上面这个模板我就想立马给各种类型的双指针场景给安排上,让我试一试这把刀锋不锋利,首先来第一种,快慢指针,我在leetcode上一下子就找到了,看看这题目怎么描述的:

3. 无重复字符的最长子串

 

不知道是不是刷题刷多了,看到题就会大概猜到这道题要用什么算法,我相信很多人都有这种感觉,一看到这题目,就知道这肯定是双指针,并且是快慢指针就能搞定。那么好,我们直接套模板,把代码写出来:

public int lengthOfLongestSubstring(String s) {
        Set<Character> containString = new HashSet<>();// 子串中包含的所有字符
        char[] sChar = s.toCharArray();
        int left = 0;
        int right = 0;
        int max = 0;
        while (right < sChar.length) {// 右指针走到最右端的时候,循环就可以结束了
            if (!containString.contains(sChar[right])) {// 满足右指针继续右移的条件
                containString.add(sChar[right]);
                max = max > right - left + 1 ? max : right - left + 1;
                right++;
            } else {// 满足左指针右移的条件
                while (containString.contains(sChar[right])) {
                    containString.remove(sChar[left]);
                    left++;
                }
            }
        }
        return max;
    }

那么好,这道题可能很多小伙伴会说太简单了,如果双指针只有这水平,那大家都可以洗洗睡了,还在算法的题海里面挣扎个什么劲。我们接着往下看第二种,收尾指针,刚好也有一道比较经典的题:

11. 盛最多水的容器

如果放在几年前,在我功力还不是那么深厚的时候,我一看这题目,果断给他来个双层循环,暴力计算出所有两个坐标之间的面积,记录一个最大值,然后比较更新,10分钟代码我就给它撸完。然后一跑,尴尬了,暴力的居然还能过,只是这速度和内存的使用情况,有点不太好看。

但是现在嘛,首尾指针给它安排上,两个指针指向的数值,比较小的往对方靠拢(为什么这样自己去想想),记录一个最大值,不断刷新满足条件的值,直到两个指针相遇,结束。

public int maxArea(int[] height) {
        int left = 0;
        int right = height.length - 1;
        int max = 0; // 记录中间过程满足条件最大值
        while (left < height.length && right > left) {// 满足指针继续移动
            int curretn = (height[left] > height[right] ? height[right] : height[left]) * (right - left);
            max = curretn > max ? curretn : max;
            if (height[left] >= height[right]) {// 右指针左移
                right--;
            } else { // 左指针右移
                left++;
            }
        }
        return max;
    }

好,前面两种都介绍完了,下面就轮到固定间距双指针了,但是尴尬的是我居然没找到相关类型的题目,额,先跳过,这种类型的题目一般是滑动窗口会用的比较多,下次遇到了我再更新到这里来,我们先看下两个指针指向不同序列这种类型,这个比较有意思,刚好之前也遇过:

56. 合并区间

class Solution {
    public int[][] merge(int[][] intervals) {
        if (intervals.length <= 1) {
            return intervals;
        }
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[0] == o2[0]) {
                    return o1[1] - o2[1];
                }
                return o1[0] - o2[0];
            }
        });

        int min = intervals[0][0];
        int max = intervals[0][1];
        List<int[]> resultList = new ArrayList<>();
        for (int i = 1; i < intervals.length; i++) {
            if (max >= intervals[i][0]) {
                // 存在交集,合并
                max = max > intervals[i][1] ? max : intervals[i][1];
                continue;
            } else {
                // 不存在交集,将min和max先入结果集,然后再重置min和max
                int[] tempResult = {min, max};
                resultList.add(tempResult);
                min = intervals[i][0];
                max = intervals[i][1];
            }
        }
        resultList.add(new int[] {min, max});

        return resultList.toArray(new int[resultList.size()][2]);
    }
}

两个指针min和max,指向不同的列,找出相交的集合,并返回。

双指针的题目一般情况下都不会很难,从我刷的题目经验来看,顶多中等题吧,关键在于有双指针解题的思想(就是看到问题第一时间能够知道使用双指针解题的思路),下面列一下在leetCode上使用双指针思想解题的题目,供大家练手:
5. 最长回文子串
11. 盛最多水的容器
15. 三数之和
18. 四数之和
26. 删除有序数组中的重复项
27. 移除元素
31. 下一个排列
83. 删除排序链表中的重复元素
160. 相交链表
283. 移动零
392. 判断子序列
821. 字符的最短距离
870. 优势洗牌
905. 按奇偶排序数组
986. 区间列表的交集

 

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

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

相关文章

数据结构——链表

目录 一、链表的定义 二、链表的基本操作 1. 单链表 1.1. 定义链表结点结构体 1.2. 定义链表类 1.3. 创建链表 1.3.1. 头插法创建链表 1.3.2. 尾插法创建链表 1.4. 遍历链表 1.5. 查找结点 1.6. 插入结点 1.7. 删除结点 1.8. 删除链表 1.9. 完整的单链表类 2. 双…

GeoServer漏洞(CVE-2023-25157)

前半部分是sql注入一些语句的测试&#xff0c;后面是漏洞的复现和利用 Sql注入漏洞 1.登入mysql。 2.查看默认数据库 3.使用mysql数据库 4.查看表 1.查看user 表 2.写注入语句 创建数据库 时间注入语句 布尔注入语句 报错注入语句 Geoserver漏洞&#xff…

45 - 多线程性能优化常见问题

1、使用系统命令查看上下文切换 上下文切换常见的监测工具 1.1、Linux 命令行工具之 vmstat 命令 vmstat 是一款指定采样周期和次数的功能性监测工具&#xff0c;我们可以使用它监控进程上下文切换的情况。 vmstat 1 3 命令行代表每秒收集一次性能指标&#xff0c;总共获取 …

Apache Doris 详细教程(二)

5、doris的查询语法 5.1、doris查询语法整体结构 SELECT [ALL | DISTINCT | DISTINCTROW ] -- 对查询字段的结果是否需要去重&#xff0c;还是全部保留等参数 select_expr [, select_expr ...] -- select的查询字段 [FROM table_references [PARTITION…

遥感方向期刊总结

开眼看期刊~ 期刊分区信息搜索网址中国科学院文献情报中心期刊分区表升级版科研通期刊查询&#xff1a; 遥感领域常见期刊Nature CommunicationsRemote Sensing of EnvironmentProceedings of the National Academy of Sciences &#xff08;PNAS&#xff09;ISPRS Journal of …

WebUI工作流插件超越ComfyUI

在AI绘画领域&#xff0c;Stable Diffsion是最受欢迎的&#xff0c;因为它是开源软件。 开源有两大优势&#xff0c;一是免费&#xff0c;二是适合折腾。 大量的开发者、爱好者投入无尽的热情&#xff0c;来推动Stable Diffsion的快速发展。 在图形界面方面&#xff0c;WebU…

排序算法介绍(一)插入排序

0. 简介 插入排序&#xff08;Insertion Sort&#xff09; 是一种简单直观的排序算法&#xff0c;它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常…

prometheus|云原生|轻型日志收集系统loki+promtail的部署说明

一&#xff0c; 日志聚合的概念说明 日志------ 每一个程序&#xff0c;服务都应该有保留日志&#xff0c;日志的作用第一是记录程序运行的情况&#xff0c;在出错的时候能够记录错误情况&#xff0c;简单来说就是审计工作&#xff0c;例如nginx服务的日志&#xff0c;kuber…

04-数据库操作对象Statement对象和PreparedStatement对象的区别,SQL注入的优缺点

Statement对象和查询结果集 Statement对象相关的方法 Connection接口中获取数据库操作对象Statement对象的方法 方法名功能Statement createStatement()创建Statement对象 Statement对象执行增删改查的SQL语句(不含占位符"?")的方法,JDBC中的SQL语句不需要提供分…

基于 ESP32 的带触摸显示屏的 RFID 读取器

如何设计一款基于 ESP32 且具有 ILI9341 触摸屏显示屏且适合壁挂式安装的美观 RFID 读取器。 本项目中用到的东西 硬件组件 ESP32 开发套件 C 1 AZ-Touch ESP 套件 1 RFID-RC522 IC卡读写器 1 ​编辑 电线、绕包线 1 详细设计流程 …

机器学习 - 导论

简单了解 机器学习关于数据集的概念 、

Autosar COM通信PDU

文章目录 Autosar 中各个PDU所在示意图PDU的分类PDU 和 SDU 的关系I-PDUN-PDUL-PDU相关协议其他参考 Autosar 中各个PDU所在示意图 PDU的分类 在Autosar 中&#xff0c;主要有 I-PDU、N-PDU和 L-PDU 三种。 L-PDU&#xff1a;Data Link Layer PDU&#xff0c;数据链路层PDUN-…

Spring-Boot---项目创建和使用

文章目录 什么是Spring-Boot&#xff1f;Spring-Boot项目的创建使用Idea创建使用网页创建 项目目录介绍项目启动 什么是Spring-Boot&#xff1f; Spring的诞生是为了简化Java程序开发的&#xff1b;而Spring-Boot的诞生是为了简化Spring程序开发的。 Spring-Boot具有很多优点…

知识点滴 - 什么是半透膜和渗透压

半透膜和渗透作用 1748年的一天&#xff0c;法国物理学家诺勒为了改进酒的制作水平&#xff0c;设计了这样一个试验&#xff1a;在一个玻璃圆筒中装满酒精&#xff0c;用猪膀胱封住&#xff0c;然后把圆筒全部浸在水中。当他正要做下一步的工作时&#xff0c;突然发现&#xff…

巧用JAVA自带的API解决日期类问题

文章目录 题目代码优势 题目 特殊日期 代码 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改 import java.time.LocalDate; public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此输入您的代…

Java 学习之多态

多态的概念 多态 晚绑定。 所谓多态&#xff0c;就是父类型的引用可以指向子类型的对象&#xff0c;或者接口类型的引用可以指向实现该接口的类的实例。 不要把函数重载理解为多态。因为多态是一种运行期的行为&#xff0c;不是编译期的行为。 多态&#xff1a;父类型的引用可…

数据在内存中的存储(含面试题)

数据在内存中的存储 1. 整数在内存中的存储2. 大小端字节序和字节序判断2.1 什么是大小端&#xff1f;2.2 为什么有大小端?2.3 练习2.3.1 练习12.3.2 练习22.3.3 练习3第一题第二题 2.3.4 练习42.3.5 练习5第一题第二题 2.3.6 练习6 1. 整数在内存中的存储 在讲解操作符的时候…

若依的基本使用

演示使用网址:若依管理系统 网站:RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|RuoYi开发文档|若依开发文档|Java开源框架…

2023/12/3总结

RabbitMq 消息队列 下载地址RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ 使用详情RabbitMQ使用教程(超详细)-CSDN博客 实现延迟队列&#xff08;为了实现订单15分钟后修改状态&#xff09; 1 死信队列 当一个队列中的消息满足下列情况之一时&…

基于hadoop下的Kafka分布式安装

简介 Kafka是一种分布式流处理平台&#xff0c;它具有高吞吐量、可扩展性、可靠性、实时性和灵活性等优点。它能够支持每秒数百万条消息的传输&#xff0c;并且可以通过增加节点来增加吞吐量和存储容量。Kafka通过将数据复制到多个节点来实现数据冗余和高可用性&#xff0c;即使…