双指针算法详解

news2024/11/15 21:39:36

什么是双指针        

        双指针算法是一种常用的算法策略,通常用于处理有序数组或链表,能够高效地解决许多问题。其核心思想是通过维护两个指针在数组或链表中移动,从而达到减少时间复杂度的目的。我们将通过三个示例代码来深入了解双指针算法的应用。

示例一:求满足 a[i] + b[j] = x 的(i,j)数对

代码示例一 

package 双指针;

import java.io.BufferedInputStream;
import java.util.Scanner;

/**
 * 求满足 a[i] + b[j] = x 的(i,j)数对
 */
public class test1 {
    private static final int N = 100000;
    private static int[] a = new int[N];
    private static int[] b = new int[N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));

        int n = sc.nextInt(); // a数组长度
        int m = sc.nextInt(); // b数组长度
        int x = sc.nextInt(); // 目标值


        for (int i = 0; i < n; i++) a[i] = sc.nextInt();
        for (int i = 0; i < m; i++) b[i] = sc.nextInt();

        int left = 0, right = m - 1;
        String result = " ";

        while (left < n && right >= 0) {
            int sum = a[left] + b[right];
            if (sum == x) {
                result = left + " " +right;
                break; // 找到唯一解后退出循环
            } else if (sum < x) {
                left++;
            } else {
                right--;
            }
        }

        // 输出结果
        System.out.println(result);
    }
}

核心逻辑解释

        在这个示例中,我们的目标是找到两个数组中的一对下标(i,j),使得它们对应的元素之和等于给定的目标值 x。

int left = 0, right = m - 1;

while (left < n && right >= 0) {
    int sum = a[left] + b[right];
    if (sum == x) {
        result = left + " " + right;
        break; // 找到唯一解后退出循环
    } else if (sum < x) {
        left++;
    } else {
        right--;
    }
}

// 输出结果
System.out.println(result);
  • 初始化两个指针 left 和 right,分别指向数组 a 的开始位置和数组 b 的结束位置。
  • 在每次循环中计算 a[left] + b[right] 的值。
    • 如果和等于 x,说明找到了一对符合条件的元素,存储结果并退出循环。
    • 如果和小于 x,将 left 右移,以尝试增大和的值。
    • 如果和大于 x,将 right 左移,以尝试减小和的值。
  • 该方法的时间复杂度为 O(n + m),而不是 O(n * m),从而提高了效率

示例二:判断子序列

代码示例二

package 双指针;

import java.io.BufferedInputStream;
import java.util.Scanner;

/**
 * 判断子序列
 */
public class test2 {
    private static final int N = 100010;
    private static int[] a = new int[N];
    private static int[] b = new int[N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        int m  = sc.nextInt();

        for (int i = 0; i < n; i++)  a[i] = sc.nextInt();
        for (int i = 0; i < m; i++)  b[i] = sc.nextInt();

        int i = 0, j = 0;
        while (i < n && j < m) {
            if (a[i] == b[j]) i++;
            j++;
        }
        if (i == n) System.out.println("Yes");
        else System.out.println("No");
    }
}

核心逻辑解释

在这个示例中,我们需要判断数组 a 是否为数组 b 的子序列。

int i = 0, j = 0;
while (i < n && j < m) {
    if (a[i] == b[j]) i++;
    j++;
}
if (i == n) System.out.println("Yes");
else System.out.println("No");
  • 使用两个指针 i 和 j 分别遍历数组 a 和 b。
  • 当 a[i] 等于 b[j] 时,表示找到了 a 中的一个元素,指针 i 向前移动,表示继续寻找 a 的下一个元素。
  • 指针 j 无论如何都会移动,用于扫描 b 中的所有元素。
  • 如果最终 i 达到了数组 a 的长度,表示数组 a 的所有元素都已在 b 中找到,此时输出 "Yes";否则输出 "No"。
  • 这种方法也具有 O(n + m) 的时间复杂度,充分利用了双指针的优势。

示例三:求数组中最长的不重复子序列

代码示例三

package 双指针;

import java.io.BufferedInputStream;
import java.util.Scanner;

import static java.lang.Math.max;

/**
 * 求数组中最长的不重复子序列
 */
public class test3 {

    private static final int N = 100010;
    private static int[] a = new int[N];//原始数组
    private static int[] b = new int[N];//记录每个数出现的次数
    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();

        for (int i = 0; i < n; i++) a[i] = sc.nextInt();

        int res = 0;
        for (int i = 0, j = 0; j < n; j++) {
            b[a[j]]++;
            while (b[a[j]] > 1) {
                b[a[i]]--;
                i++;
            }
            res = max(res, j - i + 1);

        }
        System.out.println(res);
    }
}

 核心逻辑解释

for (int i = 0, j = 0; j < n; j++) {
    b[a[j]]++;
    while (b[a[j]] > 1) {
        b[a[i]]--;
        i++;
    }
    res = max(res, j - i + 1);
}
  • 通过维护两个指针 i 和 jj 用于遍历数组,而 i 用于调整不重复元素的区间。
  • 对于每个 j,首先增加 b[a[j]] 的计数,表示该元素出现了一次。
  • 当某个元素出现次数超过 1 时,通过移动 i 指针并减少 b[a[i]] 的计数,直到所有元素都是唯一的。
  • res 用于跟踪当前最长的不重复子序列的长度。
  • 最终输出 res

总结

        双指针算法是处理数组和链表问题中非常高效的一种策略。通过上述示例,我们可以看到双指针的灵活运用可以有效解决问题,尤其是在减少时间复杂度方面优势明显。在开发过程中,熟悉双指针的应用场景将对我们解决实际问题有很大帮助。

        希望这些示例和逻辑解释能够帮助你更好地理解双指针算法。

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

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

相关文章

《动手学深度学习》笔记2.2——神经网络从基础→进阶 (参数管理-每层的权重/偏置)

目录 0. 前言 正文&#xff1a;参数管理 1. 参数访问 1.1 [目标参数] 1.2 [一次性访问所有参数] 1.3 [从嵌套块收集参数] 2. 参数初始化 2.1 [内置初始化] 2.2 [自定义初始化] 2.3 [参数绑定-共享参数] 3. 小结 4. 练习 0. 前言 课程全部代码&#xff08;pytorch版…

echarts地图的简单使用

echarts地图的简单使用 文章说明核心源码效果展示源码下载 文章说明 主要介绍echarts地图组件的简单使用&#xff0c;记录为文章&#xff0c;供后续查阅使用 目前只是简单的示例&#xff0c;然后还存在着一些小bug&#xff0c;主要是首个Legend的点击会导致颜色全部不展示的问题…

笔试编程-百战成神——Day02

1.简写单词 题目来源&#xff1a; 简写单词——牛客网 测试用例 算法原理 本题的主要难点就是如何识别每一个单词并且返回其首字母大写&#xff0c;最终组成一个新的字符串后输出&#xff0c;这里我们使用while(cin>>str)就可以解决&#xff0c;直接忽略每一个空格直接…

深入理解及如何使用main函数参数

目录 前言&#xff1a;一、main函数参数二、main函数参数的意义及如何使用三、从操作系统层面&#xff08;指令&#xff09;理解main函数参数 前言&#xff1a; 在平时编写代码的过程中&#xff0c;我们会经常写main函数&#xff0c;这是一个程序必不可少的&#xff0c;main 函…

信息汇总(避坑)系统

本系统前期设定为公司避坑系统&#xff0c;在此基础上衍生出公司信息汇总功能 主要功能点&#xff1a;避坑分类、标签、随笔记录、阅读人数、评论&#xff08;用户评论、匿名评论&#xff0c;评论回复等&#xff09;、系统留言&#xff08;支持表情留言&#xff09;、避坑信息…

JavaScript中的无穷大

JavaScript中的无穷大 溢出&#xff1a;overflow,数字结果超过JS表示的数字上限&#xff0c;结果为一个特殊的无穷大Infinity或负无穷大-Infinity. 下溢&#xff1a;underflow是当前结果无限接近于0比JS能表示的最小值还要小&#xff0c;将会返回0&#xff0c;负数下溢就是-0…

剑指offer JZ7 重建二叉树

描述&#xff1a; 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出如下图所示。 思路&#xff1a; 这道题考察的是二叉树根据先序…

蓝桥杯备赛---引言

我是来自成都锦城学院的2021级学生&#xff0c;第一次参加第十五届蓝桥杯嵌入式赛道获得了国二的名次&#xff0c;接下来将为大家分享各个模块的代码&#xff0c;可以速成省一&#xff0c;但想要取得国一的成绩则需要补偿数据结构、基本c语言函数等相关知识&#xff0c;很遗憾没…

C++ 创建型设计模式

何为设计模式 设计模式是指在软件开发中&#xff0c;经过验证的&#xff0c;用于解决在特定环 境下&#xff0c;重复出现的&#xff0c;特定问题的解决方案&#xff1b; 设计原则 依赖倒置 开放封闭 一个类应该对扩展&#xff08;组合和继承&#xff09;开放&#xff0c;对…

犀牛检测系统源码分享

犀牛检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…

python与html链接测试

做这个测试我使用了两个资源 1.csdn上收集的参考资料&#xff0c;特此感谢 链接如下&#xff1a;Pycharm社区版创建Flask项目(配置项目文件)_pycharm community flask-CSDN博客 2.kimi 网址如下&#xff1a;Kimi.ai - 帮你看更大的世界 (moonshot.cn) 这是试出来的操作步骤…

python如何查看文件的目录

1、sys.arg[0]: import sys print(sys.argv[0])#当前脚本的位置 输出结果&#xff1a; G:/Pythonxx/test.py 2、os模块 import os print("1111") print (os.getcwd())#获得当前目录 print (os.path.abspath(.))#获得当前工作目录 print (os.path.abspath(..))#获得当…

基于丹摩智算部署可图(Kolors)

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 丹摩智算平台简介一、Kolors 简介介绍技术背景部署与使用前提条件 二、DAMODEL 平台创建适配机器1.1、实例创建 三、服务部署安装 An…

性能测试利器 - Locust框架解析

01 认识Locust 说起性能测试工具&#xff0c;大家肯定想到的都是Jmeter&#xff0c;是的&#xff0c;由于其简单易用、功能强大&#xff0c;已经变成主流的压测工具之一。当需要实现一些高级功能的时候&#xff0c;可以使用Java语言对Jmeter进行扩展。 但是很多小伙伴只会Pyt…

10种数据库技术的发展历程与现状

数据库是互联网的基石&#xff0c;存储着海量信息&#xff0c;使信息可被高效地组织、检索和分享。没有数据库&#xff0c;网站无法记忆用户数据&#xff0c;应用无法提供个性化服务&#xff0c;信息交流将失去智能与连贯性。因此&#xff0c;数据库技术极大地推动了互联网的发…

如何使用 Windows 自带的虚拟机 Hyper-V

当前环境: Windows 10 Pro 开启 Hyper-V 功能 开启 Hyper-V 功能 开始菜单, 搜索 “control” 打开控制面板点击 “程序” > “启用或关闭 Windows 功能”开启所有的 Hyper-V 选项 安装虚拟机 准备系统镜像 .iso 文件 进入 itellyou.cn 进行下载所需镜像我选择的是: Wind…

nginx部署手册

1、在安装nginx前首先要确认系统中安装了gcc、pcre-devel、zlib-devel、openssl-devel yum -y install gcc pcre-devel zlib-devel openssl openssl-devel2、 新建nginx用户 &#xff08;1&#xff09;groupadd 命令用于创建一个新的用户组 groupadd nginx&#xff08;2&#…

鸿蒙开发(NEXT/API 12)【基础功能(EnterpriseAdminExtensionAbility开发指南)】企业设备管理服务

概述 企业设备管理扩展能力&#xff0c;是设备管理应用必备组件。当开发者为企业开发设备管理应用时&#xff0c;需继承EnterpriseAdminExtensionAbility&#xff0c;在EnterpriseAdminExtensionAbility实例中实现MDM业务逻辑&#xff0c;EnterpriseAdminExtensionAbility实现…