引言:算法选择的十字路口

        在算法面试中,双指针和滑动窗口如同两把瑞士军刀,能高效解决80%以上的数组和字符串问题。本文将深入解析这两种技术的核心差异,结合力扣高频题目,提供可直接复用的代码。

一、算法核心思想解析

1. 双指针技术

        双指针算法是通过维护‌两个指针变量‌(通常为数组/链表索引)协同遍历数据结构的高效策略,主要用于优化暴力解法的时空复杂度。

三种经典模式‌:

  • 对撞指针‌:首尾指针向中间收敛(如三数之和)
  • 快慢指针‌:同向移动但速度不同(如环形链表检测)
  • 滑动窗口‌:动态维护子区间(特殊双指针实现)

2. 滑动窗口技术

        作为双指针的特殊形式,滑动窗口具有以下特点:

  • 两个指针‌同向移动‌且‌维护一个连续区间
  • 通过窗口扩张/收缩动态调整解空间

3. 算法特性对比

特性

双指针算法

滑动窗口算法

指针移动方向

可对撞/同向

严格同向移动

数据要求

常需排序

原始数据即可

时间复杂度

O(n)~O(n²)

O(n)

典型问题

有序数组组合问题

子串/子数组最优解

状态维护

通常不需要

需要哈希表记录状态

二、高频面试题分类精讲

1. 双指针经典题型三数之和(LeetCode 15

解题思路

1. 暴力解法(不推荐)

最直观的方法是三重循环遍历所有可能的三元组,时间复杂度为O(n³),效率太低。

2. 排序 + 双指针法(推荐)

步骤如下:

  1. 排序数组‌:首先将数组排序,这样可以利用有序性来优化搜索
  2. 固定一个数‌:遍历数组,将当前元素作为第一个数
  3. 双指针搜索‌:在当前元素后面的部分使用双指针(左指针从当前元素后一位开始,右指针从数组末尾开始)寻找另外两个数
  4. 去重处理‌:跳过重复的元素以避免重复解

时间复杂度‌:O(n²)(排序O(nlogn) + 双指针遍历O(n²))

public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();int length = nums.length;if (nums == null || length < 3) {return result;}Arrays.sort(nums);  // 关键步骤:排序for (int i =0; i < length; i++) {// 需要和上一次枚举的数不相同if (i > 0 && nums[i] == nums[i - 1]) {continue;}int left = i+1;int right = length - 1;int target = -nums[i]; // nums[left] + nums[right] = targetwhile(left < right) {int sum = nums[left] + nums[right];if (sum == target) {result.add(Arrays.asList(nums[i], nums[left], nums[right]));// 跳过重复的left和rightwhile (left < right && nums[left] == nums[left + 1]) left++;while (left < right && nums[right] == nums[right - 1]) right--;left++;right--;} else if (sum < target) {left++;} else {right--;}}}return result;}

2. 滑动窗口经典题型最小覆盖子串(LeetCode 76

算法核心思想

滑动窗口(Sliding Window)算法‌是解决最小覆盖子串问题的最优方法:

  1. 双指针定义窗口‌:使用leftright两个指针表示当前考察的子串窗口
  2. 哈希表记录需求‌:使用两个哈希表分别存储:
  • need:目标字符串T中各字符的需求量
  • window:当前窗口中满足需求的字符数量

      3. 动态扩展收缩窗口‌:

  • 先扩展right指针寻找可行解
  • 再收缩left指针优化解

      4. 有效字符计数‌:通过valid变量统计窗口中已满足需求的字符种类数

      5. 实时更新结果‌:每当找到更小的满足条件的子串时更新结果

复杂度分析

  • 时间复杂度‌:O(n),其中n是字符串S的长度
  • 空间复杂度‌:O(m),其中m是字符集大小(通常为常数级)

Java实现代码

public String minWindow(String s, String t) {// 边界条件检查if (s == null || t == null || s.length() < t.length()) {return "";}// 初始化需求哈希表,记录t中每个字符出现的次数Map<Character, Integer> need = new HashMap<>();for (char c : t.toCharArray()) {need.put(c, need.getOrDefault(c, 0) + 1);}// 初始化窗口哈希表,记录当前窗口中满足需求的字符数量Map<Character, Integer> window = new HashMap<>();// 记录窗口中满足need条件的字符个数int valid = 0;// 记录最小覆盖子串的起始位置和长度int start = 0, minLen = Integer.MAX_VALUE;// 滑动窗口左右指针int left = 0, right = 0;while (right < s.length()) {// 获取右指针当前字符char c = s.charAt(right);// 右指针向右移动right++;// 如果当前字符在需求表中,则更新窗口计数if (need.containsKey(c)) {window.put(c, window.getOrDefault(c, 0) + 1);// 如果窗口中该字符数量等于需求数量,则valid加1if (window.get(c).equals(need.get(c))) {valid++;}}// 当窗口满足所有字符需求时,尝试收缩左边界while (valid == need.size()) {// 更新最小覆盖子串信息if (right - left < minLen) {start = left;minLen = right - left;}// 获取左指针当前字符char d = s.charAt(left);// 左指针向右移动left++;// 如果移出的字符在需求表中,则更新窗口计数if (need.containsKey(d)) {// 如果窗口中该字符数量刚好等于需求数量,则valid减1if (window.get(d).equals(need.get(d))) {valid--;}window.put(d, window.get(d) - 1);}}}// 返回最小覆盖子串,如果没有找到则返回空字符串return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);}

、算法选择的核心判别特征

1. 双指针算法的识别特征

当问题呈现以下‌至少两个‌特征时,优先考虑双指针算法:

  • 线性序列结构‌(数组/链表)
    • 典型表现:输入数据为数组或链表等线性结构
    • 反例:树形结构或图结构通常不适用
  • 有序性或可排序性
    • 典型表现:题目明确说明"已排序"或允许预处理排序
    • 示例特征:"非递减顺序排列"、"你可以假设数组已经按升序排列"
  • 对称性/双向操作需求
    • 典型表现:需要从两端向中间或特定方向协同操作
    • 示例场景:回文判断、盛水容器问题
  • 组合优化问题
    • 典型表现:需要寻找两个或多个元素的特定组合
    • 示例模式:"找出满足条件的两个元素"、"确定三个数的组合"

2. 滑动窗口算法的识别特征

当问题呈现以下‌至少两个‌特征时,优先考虑滑动窗口算法:

  • 连续子区间要求
    • 典型表现:需要处理数组中连续的序列或子串
    • 关键词:"连续子数组"、"子串"、"连续的...满足条件"
  • 窗口可变或固定大小
    • 典型表现:需要动态调整或保持固定大小的区间
    • 可变窗口特征:"最短/最长满足条件的..."
    • 固定窗口特征:"大小为k的..."
  • 统计类约束条件
    • 典型表现:基于频率、和、平均值等统计量的条件判断
    • 示例条件:"包含所有字符"、"和≥target"、"无重复字符"
  • 最优解搜索
    • 典型表现:需要寻找满足特定条件的最优区间
    • 典型目标:"最小的...满足..."、"最大的...满足..."

3. 特征验证案例

案例1:三数之和(双指针)

  • ✅ 线性结构(数组)
  • ✅ 可排序性(题目允许排序)
  • ✅ 组合问题(找三个数)
  • ✅ 对称操作(需要跳过重复解)

案例2:最小覆盖子串(滑动窗口)

  • ✅ 连续子区间(子串要求连续)
  • ✅ 可变窗口(找最短满足条件的)
  • ✅ 统计条件(包含所有字符)
  • ✅ 最优解搜索(最小窗口)

4. 应用场景选择指南

1. 优先选择双指针的情况
  • 有序数组的组合问题‌:如两数之和、三数之和
  • 链表操作‌:如环形链表检测、链表中点定位
  • 对称性问题‌:如回文串验证、反转字符串‌
2. 优先选择滑动窗口的情况
  • 连续子序列问题‌:如最小覆盖子串、最长无重复子串
  • 区间统计问题‌:如和大于等于目标值的最短子数组
  • 固定窗口大小问题‌:如大小为k的子数组的最大平均值‌

、力扣经典案例

4.1、基础双指针问题

4.1.1. 对撞指针经典题
  • 167. 两数之和 II - 输入有序数组
    • 解法特点:有序数组相向指针遍历
    • 时间复杂度:O(n)
  • 344. 反转字符串
    • 解法特点:原地操作字符数组
    • 空间复杂度:O(1)

4.2、滑动窗口常规问题

4.2.1. 可变窗口基础题
  • 209. 长度最小的子数组
    • 解法特点:动态调整窗口大小
    • 关键点:维护窗口和与目标值的比较
4.2.2. 哈希表辅助窗口题
  • 3. 无重复字符的最长子串
    • 解法特点:哈希表记录字符最后出现位置
    • 时间复杂度:O(n)

4.3、字符串匹配问题

4.3.1. 困难级窗口问题
  • 76. 最小覆盖子串
    • 解法特点:精确的窗口收缩条件
    • 关键点:有效字符计数机制
4.3.2. 固定窗口典型题
  • 438. 找到字符串中所有字母异位词
    • 解法特点:固定长度窗口滑动
    • 优化点:数组替代哈希表统计字符

4.4、链表双指针问题

4.4.1. 快慢指针经典题
  • 141. 环形链表
    • 解法特点:Floyd判圈算法
    • 空间复杂度:O(1)

4.4.2. 前后指针应用

  • 19. 删除链表的倒数第 N 个结点
    • 解法特点:前后指针保持固定间距
    • 关键点:虚拟头节点处理边界

4.5、多维滑动窗口问题

4.5.1. 单调队列配合题
  • 239. 滑动窗口最大值
    • 解法特点:单调递减队列维护窗口极值
    • 时间复杂度:O(n)
4.5.2. 双堆进阶问题
  • 480. 滑动窗口中位数
    • 解法特点:大小顶堆平衡维护中位数
    • 关键点:延迟删除策略

结语:算法精进的阶梯

掌握双指针和滑动窗口不仅是面试的敲门砖,更是提升算法思维的关键。建议读者按照解题模板→理解原理→独立实现→优化变体的路径系统学习,逐步构建自己的算法兵器库。

附高频核心算法

动态规划(DP):从核心场景识别到优化技巧

堆排序:原理、实现与优化

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果MAC、MacBook air和pro安装windows双系统与iOS分发

文章目录1. main1.1 准备工作1.2 启动转换助理1.3 Windows安装1.4 苹果电脑安装Windows双系统切换2. 苹果(iOS)分发/上架2.1 上架App Store2.2 上架TestFlight2.3 webClip免签上架2.4 超级签名2.5 企业证书2.6 app分发系统Reference1. main 苹果电脑安装windows双系统 https:…

ArcGIS定向影像(1)——非传统影像轻量级解决方案

常常听到这样的需求&#xff0c;ArcGIS能让用户自己低成本的做出谷歌街景吗&#xff1f;现在 _ArcGIS Pro 3.2 和 ArcGIS Enterprise 11.2 _能够让用户不使用任何插件和扩展的情况下完成街景数据集的构建&#xff0c;数据管理&#xff0c;发布服务和调用的完整解决方案。非常体…

uni-app 网络之封装实战HTTP请求框架

前言在uniapp开发中&#xff0c;网络请求是每个应用都必不可少的功能模块。一个优秀的网络请求封装不仅能提高开发效率&#xff0c;还能增强代码的可维护性和可扩展性。本文将基于实际项目经验&#xff0c;详细介绍如何封装一个高效、可维护的Uniapp网络请求框架&#xff0c;并…

架构师成长之路-架构方法论

文章目录前言一、先搞懂&#xff1a;架构师不仅仅是“技术大佬”&#xff0c;更是“问题解决者”1.1 架构师的分类&#xff1a;不止“开发架构师”一种1.2 架构师要关注什么&#xff1f;别只盯着技术1.3 架构师解决问题的4步心法&#xff1a;从定义到落地1.4 架构师的成长攻略&…

uniapp在微信小程序中实现 SSE 流式响应

前言 最近需要使用uniapp开发一个智能对话页面&#xff0c;其中就需要使用SSE进行通信。 本文介绍下在uniapp中如何基于uni.request实现SSE流式处理。 在线体验 #小程序:yinuosnowball SSE传输格式 返回输出的流式块: Content-Type为text/event-stream 每个流式块均为 d…

STM32N6AI资料汇总

文章目录前言一、STM32N6硬件资源1.1 NUCLEO-N657X0-Q1.2 STM32N6570-DK1.3 正点原子STM32N647二、STM32N6软件资源2.1 STM32CubeN6例程资源包2.2 STM32图像信号处理器&#xff08;ISP&#xff09;调优软件2.3 正点原子N6开发板配套软件三、AI软件资源3.1 STM32N6 AI软件包总结…

Flask学习笔记(一)

1、环境准备pip install Flask使用Flask开发第1个入门程序&#xff1a;from flask import Flask app Flask(__name__) app.route(/) def hello_world():return Hello, World!if __name__ __main__:app.run()Flask构造函数将当前模块的名称(__name__)作为参数。2、route函数ap…

CSP认证练习题目推荐(4)

思维、贪心、综合 排队打水 这道题目不算难&#xff0c;但是不注意还是会出现很多错误&#xff0c;比如结构体的书写。以及自定义结构体排序。还有这里做的优化&#xff0c;使用前缀和记录打水的等待时间&#xff0c;但是这里很容易出错的点在于等待时间是应该是记录的前一个…

MySQL 视图的更新与删除:从操作规范到风险防控

MySQL 视图的更新与删除&#xff1a;从操作规范到风险防控 视图作为 “虚拟表”&#xff0c;其更新与删除操作常常让开发者困惑 ——“为什么更新视图会报错&#xff1f;”“删除视图会不会弄丢数据&#xff1f;” 实际上&#xff0c;80% 的视图操作问题都源于对 “视图依赖基表…

C 语言实现 I.MX6ULL 点灯(续上一篇)、SDK、deep及bsp工程管理

目录 一、汇编点灯转 C 语言实现 1. 关键字&#xff1a;volatile 2. 寄存器地址定义&#xff08;两种方式&#xff09; &#xff08;1&#xff09;直接宏定义地址 &#xff08;2&#xff09;结构体封装寄存器&#xff08;优化访问&#xff09; 3. 核心功能代码 &#xff…

DevOps实战(7) - 使用Arbess+GitPuk+sourcefare实现Node.js项目自动化部署

Arbess 是一款国产开源免费的 CI/CD 工具&#xff0c;工具支持一键部署&#xff0c;页面简洁易用。本文将详细介绍如何安装配置使用GitPuk、sourcefare、Arbess系统&#xff0c;使用流水线拉取GitPuk源码、使用sourcefare代码扫描、构建安装包并进行主机部署。 1、GitPuk 安装…

算法,蒜鸟蒜鸟-P1-理解“双指针”

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录引言1 双指针&#xff1a;Two Pointers1.1 左右指…

使用cookiecutter创建python项目

一、关于Python项目结构Python 项目并没有完全统一的 “固定结构”&#xff0c;但行业内有一些广泛遵循的约定俗成的目录结构&#xff08;尤其针对可分发的包或大型项目&#xff09;。同时&#xff0c;确实有工具可以快速生成这些标准化结构&#xff0c;提高开发效率&#xff0…

台积电生态工程深度解析:从晶圆厂到蜂巢的系统架构迁移

当半导体巨头将工厂视为生态系统&#xff0c;用工程思维解决环境问题概述&#xff1a;生态系统的工程化再造台积电近日开展的"积蜜"项目绝非简单的企业CSR行为&#xff0c;而是一场将生态系统视为复杂系统进行工程化改造的技术实践。本文将从系统架构、数据监控、循环…

从零实现一个简易计算器

最近在刷算法题时&#xff0c;遇到了实现计算器的问题。一开始觉得很简单&#xff0c;但真正动手实现时才发现其中有很多细节需要考虑。今天就来分享一下我的实现思路和学到的经验。问题分析我们需要实现一个能够处理加减乘除四则运算的计算器&#xff0c;要正确处理运算符的优…

Actix-webRust Web框架入门教程

文章目录引言Actix-web是什么&#xff1f;准备工作你的第一个Actix-web应用理解代码结构处理请求和响应接收请求数据返回响应中间件 - 增强你的应用状态管理和依赖注入实用示例&#xff1a;构建RESTful API测试你的Actix-web应用部署Actix-web应用结语额外资源引言 嘿&#xf…

若依框架前端通过 nginx docker 镜像本地运行

1. 前言 项目运行过程图&#xff1a;对于前端项目通过命令 npm run build 打包后&#xff0c;无法直接运行。存在如下错误&#xff1a;可以通过配置 nginx 服务器运行前端项目解决如上问题。 2. Nginx 运行 采用 docker 镜像的方式运行&#xff0c;docker-compose.yml 文件内容…

浅聊一下HTTP协议

在日常上网浏览网页、刷视频时&#xff0c;背后都离不开 HTTP 协议的支持。作为 Web 世界的 “交通规则”&#xff0c;它负责服务器和客户端浏览器之间的数据传输。这篇文章就带大家全面了解 HTTP 协议&#xff0c;从基本概念到通信细节&#xff0c;再到安全相关的 HTTPS&#…

机器人控制器开发(定位——cartographer ros2 使用2)

文章总览 1 纯定位模式 当完成建图后&#xff0c;会生成pbstream格式的地图文件 配置纯定位模式的lua脚本 backpack_2d_localization.lua include "backpack_2d.lua"TRAJECTORY_BUILDER.pure_localization_trimmer {max_submaps_to_keep 3, } POSE_GRAPH.optimi…

《大数据之路1》笔记3:数据管理

一 元数据 1.1 元数据概述 定义&#xff1a; 元数据是关于数据的数据&#xff0c;元数据打通了源数据、数据仓库、数据应用&#xff0c;记录了数据从生产到消费的全部过程。元数据主要记录数据仓库中模型的定义、各层级间的映射关系、监控数据仓库的数据状态和ETL的任务运行状态…