发现算法之美-双指针之对撞指针

『算法』——双指针算法——快慢指针/对撞指针/滑动窗口(快慢指针的一种) 双指针算法引言1、对撞指针2、快慢指针3、滑动窗口 引言 什么是双指针? \quad \quad严格的来说,双指针只能说是是算法中的一种技巧。双指针指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。 \quad \quad双指针算法在一些数组题中很常用,双指针算法有两种形式,一种被称为对撞指针,两个指针从两端向中间靠拢;另一种是快慢指针,两个指针向统一方向运动,滑动窗口方法就是一种常用的快慢指针方法。 快慢 阅读详情

在这里插入图片描述

  • 什么是对撞指针?
    • 初识
    • 算法图
    • 对撞过程图
  • JavaScript中的Array与对撞指针
    • 在js中,如何定义对撞指针?
    • 实现一个最简对撞指针
  • leetcode 对撞指针 解法题目
    • 7.整数反转(easy)
    • 9.回文数(easy)
    • 27.移除元素(easy)
    • 125.验证回文串(easy)
    • 167.两数之II-输入有序数组(easy)
    • 190.颠倒二进制位(easy)
    • 344.反转字符串(easy)
    • 345.反转字符串中的元音字母(easy)
    • 11.盛水最多的容器(medium)

什么是对撞指针?

初识
  • 对撞指针是双指针算法之一。
  • 对撞指针从两端向中间迭代数组。一个指针从始端开始,另一个从末端开始。
  • 对撞指针的终止条件是两个指针相遇。
  • 对撞指针常用于排序数组。
算法图

image

对撞过程图

167.两数之II-输入有序数组(easy)的对撞过程图。
蓝色指针:头指针 红色指针:尾指针 终止条件:头尾指针对撞

JavaScript中的Array与对撞指针

在js中,如何定义对撞指针?
命名

头尾指针的命名可以为:

  • i, j
  • head, tail
  • start, end
初始值
  • 头指针:0
  • 尾指针:数组长度减一
let arr = [1, 7, 5, 2];
let head = 0;
let tail = arr.length -1;
实现一个最简对撞指针

image

var arr = new Array(10).fill(0).map((num,i)=>num+i);
var i =0;
var j = arr.length - 1;
while(i<j){
  i++;
  j--;
}
var collision = [i - 1, j + 1]
var tip = `Array's head and tail had a collision between ${collision[0]} and ${collision[1]}`;
console.log(tip); // Array's head and tail had a collision between 4 and 5

leetcode 对撞指针 解法题目

  • 7.整数反转(easy)
  • 9.回文数(easy)
  • 27.移除元素(easy)
  • 125.验证回文串(easy)
  • 167.两数之II-输入有序数组(easy)
  • 190.颠倒二进制位(easy)
  • 344.反转字符串(easy)
  • 345.反转字符串中的元音字母(easy)
  • 11.盛水最多的容器(medium)
7.整数反转(easy)

题目:https://leetcode-cn.com/problems/reverse-integer/
题解:https://github.com/FrankKai/leetcode-js/blob/master/7.Reverse_Integer.js

var reverse = function (x) {
  /**
   * 解法2.指针对撞法
   * 性能:96 ms 35.38% 35.9 MB 77.35%
   */
  var sign = Math.sign(x);
  var arr = x.toString().split("");
  //
  if (sign === -1) {
    arr.shift();
  }
  // 指针对撞开始
  var i = 0;
  var j = arr.length - 1;
  while (i < j) {
    swap(arr, i, j);
    i++;
    j--;
  }
  function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
  // 指针对撞结束
  var rX = parseInt(arr.join(""));
  var result = sign * rX;
  var min = -Math.pow(2, 31);
  var max = Math.pow(2, 31) - 1;
  if (rX < min || rX > max) return 0;
  return result;
};
9.回文数(easy)

题目:https://leetcode-cn.com/problems/palindrome-number/
题解:https://github.com/FrankKai/leetcode-js/blob/master/9.Palindrome_Number.js

var isPalindrome = function (x) {
  /**
   * 解法3:对撞指针法
   * 性能:244ms 45.5MB
   */
  var strArr = `${x}`.split("");
  var i = 0;
  var j = strArr.length - 1;
  while (i < j) {
    if (strArr[i] !== strArr[j]) {
      return false;
    }
    i++;
    j--;
  }
  return true;
};
27.移除元素(easy)

题目:https://leetcode-cn.com/problems/remove-element/
题解:https://github.com/FrankKai/leetcode-js/blob/master/27.Remove_Element.js

var removeElement = function (nums, val) {
  /**
   * 解法2:对撞指针
   * 性能:64ms 33.9MB
   */
  var i = 0;
  var j = nums.length - 1;
  while (i <= j) {
    if (nums[i] === val) {
      nums.splice(i, 1);
      j--;
    } else if (nums[j] === val) {
      nums.splice(j, 1);
      j--;
    } else {
      i++;
    }
  }
  return nums.length;
};
125.验证回文串(easy)

题目:https://leetcode-cn.com/problems/valid-palindrome/
题解:https://github.com/FrankKai/leetcode-js/blob/master/125.Valid_Palindrome.js

var isPalindrome = function (s) {
  /**
   * 解法1:正则 + 对撞指针
   * 性能:76ms 89.76% 37.5MB 70.83%
   */
  var parlinDrome = s.replace(/[^\w]/g, "").replace(/_/g, "").toLowerCase();
  var strArr = parlinDrome.split("");
  var i = 0;
  var j = strArr.length - 1;
  while (i < j) {
    if (strArr[i] !== strArr[j]) {
      return false;
    }
    i++;
    j--;
  }
  return true;
};
167.两数之II-输入有序数组(easy)

题目:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/
题解:https://github.com/FrankKai/leetcode-js/blob/master/167.Two_Sum_II-Input_array_is_sorted.js

var twoSum = function (numbers, target) {
  /**
   * 解法2:对撞指针
   * 性能:68ms 71.18% 35.2MB 76.60%
   * 时间复杂度:O(n^2)
   */
  var left = 0;
  var right = numbers.length - 1;
  while (left < right) {
    if (numbers[left] + numbers[right] === target) {
      return [left + 1, right + 1];
    } else if (numbers[left] + numbers[right] > target) {
      right--;
    } else {
      left++;
    }
  }
};
190.颠倒二进制位(easy)

题目:https://leetcode-cn.com/problems/reverse-bits/
题解:https://github.com/FrankKai/leetcode-js/blob/master/190.Reverse_Bits.js

/**
 * @param {number} n - a positive integer
 * @return {number} - a positive integer
 */
var reverseBits = function (n) {
  /**
   * 解法1:转数组后对撞交换位置
   * 性能:76ms 35.8MB
   * 思路:
   * 十进制转二进制:toString(2)
   * 32位空位补0:padStart(32,0)
   * 反转算法:对撞指针法
   * 二进制转十进制:parseInt(,2)
   */
  let arr = n.toString(2).padStart(32, 0).split("");
  let head = 0;
  let tail = arr.length - 1;
  while (head < tail) {
    swap(arr, head, tail);
    head++;
    tail--;
  }
  function swap(arr, i, j) {
    let temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
  let result = parseInt(arr.join(""), 2);
  return result;
};
344.反转字符串(easy)

题目:https://leetcode-cn.com/problems/reverse-string/
题解:https://github.com/FrankKai/leetcode-js/blob/master/344.Reverse_String.js

var reverseString = function (s) {
  /**
   * 解法2:对撞指针
   */
  var headIdx = 0;
  var tailIdx = s.length - 1;
  while (headIdx < tailIdx) {
    swap(s, headIdx, tailIdx);
    headIdx++;
    tailIdx--;
  }
  function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
  return s;
};
345.反转字符串中的元音字母(easy)

题目:https://leetcode-cn.com/problems/reverse-vowels-of-a-string/
题解:https://github.com/FrankKai/leetcode-js/blob/master/345.Reverse_Vowels_of_a_String.js

/**
 * @param {string} s
 * @return {string}
 */
var reverseVowels = function (s) {
  /**
   * 解法1:对撞指针
   * 性能:108 ms 31.59% 38.4 MB 66.67%
   */
  var univocalic = ["a", "e", "i", "o", "u", "A", "E", "I", "O", "U"];
  var sArr = s.split("");
  var head = 0;
  var tail = sArr.length - 1;
  while (head < tail) {
    if (univocalic.includes(sArr[head]) && univocalic.includes(sArr[tail])) {
      swap(sArr, head, tail);
      head++;
      tail--;
    } else if (!univocalic.includes(sArr[head])) {
      head++;
    } else if (!univocalic.includes(sArr[tail])) {
      tail--;
    }
  }
  function swap(arr, i, j) {
    var temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
  }
  return sArr.join("");
};
11.盛水最多的容器(medium)

题目:https://leetcode-cn.com/problems/container-with-most-water/
题解:https://github.com/FrankKai/leetcode-js/blob/master/11.Container_With_Most_Water.js

var maxArea = function (height) {
  /**
   * 解法1:对撞指针法
   * 性能:64ms 35.6MB
   * */
  var head = 0;
  var tail = height.length - 1;
  var maxCapacity = 0;
  while (head < tail) {
      maxCapacity = Math.max(Math.min(height[head], height[tail]) * (tail - head), maxCapacity)
      if (height[head] < height[tail]) {
          head++
      } else {
          tail--;
      }
  }
  return maxCapacity;
};

期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组:

努力成为优秀前端工程师!

算法思想之双指针 服务之间交换的接口成功率作为服务调用关键质量特性,某个时间段内的接口失败率使用一个数组表示,数组中每个元素都是单位时间内失败率数值,数组中的数值为 0 ~ 100 的整数,给定一个数值(minAverageLost)表示某个时间段内平均失败率容忍值,即平均失败率小于等于 minAverageLost,找出数组中最长时间段,如果未找到则直接返回。接下来的第 2 行到第 N + 1 行(共 N 行),每行为一个正整数,表示第 i 块披萨的大小,其中 1 ≤ i ≤ N。判定 S 是否是 L 的有效子串。 阅读详情

相关推荐

双指针算法详解

【快慢指针】有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在⼀个位置上。其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快 慢指针的思想。如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会。在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的。常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。

pzn2506的博客 1569

【算法】关于双指针的奇技淫巧(一):对撞指针

说明两数之和应该还要往上增加,而此时尾指针所指向的数已经是最大了,所以需要让头指针往右移动才可以使得两数之和往上增加,继而推断出头指针所指向的“2” 与尾指针指向的“6、10、12、15”都不符合,因为“15”已经是最大都不符合目标数,其他比它小的数就更不用说。10 + 15 = 25 > 22,只要看明白上面说的原理,这里理解起来也很简单,就是。判断一下当前数值相加是否符合目标数,2 + 15 = 17 > 9 ,两数之和比目标数要大,所以要让两数之和减少,因为头指针所指向的数已经是最小的了。

师兄怎么办 827

Xilinx Vitis 2020.1头文件路径配置避坑指南:解决#include找不到文件的常见问题

本文针对Xilinx Vitis 2020.1开发环境中常见的#include头文件找不到问题,提供了系统的避坑指南。文章深入解析了Vitis的头文件搜索机制,对比了通过工程属性GUI、修改编译命令及使用环境变量三种配置方法的优劣与隐藏陷阱,并给出了高级场景的排查流程与工程结构最佳实践,帮助开发者高效解决路径配置难题。

weixin_28831399的博客 570

基础算法(1)——双指针

算法题:移动零、复写零、快乐数、盛水最多的容器、有效三角形的个数、查找总价格为目标值的两个商品、三数之和、四数之和

Yuan_o_的博客 1804

无源定位之时差估计的精确时差估计算法(ETDE)及MATLAB实现程序

时差估计算法之精确时差估计(ETDE)欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想

伊谢尔伦的林中小路 4255

C语言—for循环打印矩形,正三角形,倒三角形,九九乘法,等腰三角形,倒着的等腰三角形(简易版代码)(重点考察for循环嵌套)

本章节教大家如何利用for循环打印正三角形,倒三角形,九九乘法表及等腰三角形(简易版代码)说明:1、循环语句的循环体内又包含另一个完整的循环结构,称为循环结构的嵌套。内嵌的循环语句中还可以再嵌套循环结构,这样就形成多重循环结构的嵌套。2、for 语句、while 语句和 do-while 语句都允许嵌套。三种循环语句可以相互嵌套。3、内层的循环语句必须完全被包含在外层的循环体中,不能发生交叉。

m0_63501145的博客 1695

算法经典:对撞指针(此指针非彼指针)

双指针分为三种: (1)普通指针:多是两个指着往同一个方向移动(无快慢之分) (2)对撞指针:两个指针,一个位于头,一个位于尾,它们向中间移动(主要应用于有序数组) (3)快慢指针:两个指针,起始点位于开头,当A条件成立时,A指针++; 同理:当B条件成立时,B指针++(其中A,B的条件束缚不同因此产生快慢之分) 我们这里来介绍第二种(2)对撞指针: 第一个例子:找相应数字求和==一个特值: 题目:给定一个有序数组(数组是递增的),如数组arr = {1,4,5,7,9};找两个数之和为12,

lihua777的博客 1569

LVGL8.x 实体按键与Keypad驱动的无缝对接实战

本文详细解析了LVGL8.x中实体按键与Keypad驱动的两种对接方案:坐标映射的Button方式与事件驱动的Keypad方式。重点阐述了如何模块化裁剪lv_port_indev.c模板文件,并深入讲解了Keypad驱动与Group焦点管理系统的核心协作机制,为无触摸屏的嵌入式设备提供流畅的UI交互解决方案。

weixin_29164497的博客 446

对撞指针

对撞指针是双指针的一种。对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。对撞数组适用于有序数组,也就是说当你遇到题目给定有序数组时,应该第一时间想到用对撞指针解题。 例题 167. 两数之和 II - 输入有序数组 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 函数应该返回这两个下...

ldrrr的博客 1156

LPDDR4协议规范之 (四)命令和时序

LPDDR4协议规范之 (四)命令和时序命令真值表激活操作读写访问操作读前沿和后沿突发读取操作流程读操作时序写前沿和后沿突发写操作写入均衡(待更新) 命令真值表 激活操作 ACTIVATE命令由两个连续命令组成,Activate-1命令和Activate-2。通过在(Activate-1)时钟的第一个上升沿保持CS HIGH,CA0 HIGH和CA1 LOW来发出Activate-1命令,通过...

YJFeiii的博客 2万+

(Linux)DHCP 超级作用域和中继代理(超难受做了超久)

DHCP服务器在192.168.159.0 可以实现分配IP的功能,现在要跨网段分配IP 就需要用到DHCP中继代理。中继代理有两张网卡分别eth0:IP 192.168.159.2 ;eth1: IP:192.168.200.2 。现在要实现192.168.200.0网段的客户机可以获取DHCP服务器的IP。中继代理其实是相当于一个路由器的作用 DHCP服务器的IP地址 :192.168.159...

DJ_joker的博客 2224

算法技巧——双指针算法

前置知识 C 和 C++ 的数组、指针。 什么是双指针 严格的来说,双指针只能说是是算法中的一种技巧。 双指针指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。 双指针问题套路 通俗的说,就是在数组遍历中,我们使用两个指针进行操作。所以双指针问题基本有以下几个细节: 1、双指针的初始位置。根据双指针的分类,有两种可能。具体看下面的介绍。 2、双指针的移动方法。根据双指针的分类,有两种可能。具体

努力中的老周的专栏 1万+

Vue2项目实战:vue2-org-tree实现动态组织架构图

本文详细介绍了如何在Vue2项目中使用vue2-org-tree组件实现动态、可交互的组织架构图。内容涵盖从快速安装、基础渲染到核心功能实战,包括水平布局、节点展开折叠、响应式数据绑定、深度自定义节点内容以及事件处理。同时提供了性能优化、样式覆盖等避坑指南,并通过一个完整的企业级Demo展示了如何打造功能丰富的架构图,助力高效开发后台管理系统。

weixin_28040125的博客 522

算法——双指针

双指针的简单介绍及四种常用解题模型

雪月清的博客 1万+

手把手教你完成YOLOv11分类识别界面搭建,使用Qt6设计YOLOv11分类识别系统,前台系统+后台管理系统开发实战,全网最详细教程

本项目结合YOLOv11分类识别算法和PySide6框架,开发了一套图形化分类识别系统。系统支持图片、视频和摄像头实时分类检测,并具备完善的用户管理功能,包括登录验证、个人信息修改等模块。最新版本新增了管理员后台管理系统,包含用户管理、权限控制等功能。系统采用MySQL数据库存储用户数据,界面设计采用QtDesigner完成,实现了高效的目标分类与友好的交互体验。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1050

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【算法】【优选算法】双指针(上)

结合算法题理解双指针算法

yj20040627的博客 3332

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

优选算法《双指针》

在这些算法中我们先来了解的是一些非常经典且较为常用的算法,在此也就是优选出来的算法,接下来在每一篇章中我们都会来学习一种优选算法,并且在了解了算法原理之后接下来会通过几道算法题来巩固相应的算法原理。在每道算法题的讲解中都会通过。三步来带你完全吃透每道算法题,相信通过这一系列算法专题的学习,你的算法以及代码能力会有质的飞跃。接下来就开始本篇双指针专题算法的学习吧!在学习了C/C++的基础知识之后接下来我们就可以来系统的学习相关的算法了,这在之后的。

mljy.博客 3735

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

双指针算法

双指针算法介绍,包含原理和相关例题代码实现!

涛涛的个人博客 3万+

算法【Java】—— 双指针算法

用Java 语言实现双指针算法

熵减玩家 4690

【算法】基础算法001之双指针

本篇文章主要会讲解双指针的思想,双指针是一种非常优秀的算法思想,有对撞指针和快慢指针两种基本用法。双指针对于有序数据的处理是比较有优势的,当你遇到有序的数据时,你可以尝试着利用双指针或者二分来解题,当然本篇文章只会讲解双指针。那么双指针思想具体的应用,以及为什么双指针适用于有序数组的处理呢?

℉f的博客 2696

算法:双指针(快慢指针|对撞指针)、快排、模拟、二分、贪心

定义:双指针算法是一种常用的算法技巧,通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作。实现:双指针并非真的用指针实现,一般用两个变量来表示下标。应用场景:双指针算法使用两个指针在数据结构上进行迭代,并根据问题的要求移动这些指针。双指针往往与单调性、排序联系在一起,可以优化时间复杂度从O(n^2)到O(n)。常见模型对撞指针快慢指针定义:两个指针left和right分别指向序列的第一个元素和最后一个元素。然后left指针不断递增,right指针不断递减。

m0_74161592的博客 1407

【算法】双指针

常见的双指针有两种形式,⼀种是对撞指针,⼀种是快慢指针。

春风不语。 4093

算法专题一: 双指针

常见的双指针有两种形式,一种是对撞指针,一种是左右指针。

酷酷学!!!的博客 2457

【算法专题】双指针

算法专题---双指针

YoungMLet的博客 1738

【优选算法 | 双指针】双指针大揭秘:如何用两根指针优化你的代码

在本篇文章中,我们将深入探索双指针算法的奥秘。从基础概念到实际应用,带你全面了解如何利用两根指针高效解决各种编程问题。无论你是刚接触算法的新人,还是希望提升代码性能的老手,双指针都是你不可忽视的利器!

专注于 C/C++ 后端开发,涵盖基础语法、Linux系统与网络、MySQL数据库、常见算法及项目经验。 7856

【优选算法篇】双指针的优雅舞步:C++ 算法世界的浪漫探索

这篇文章以双指针技巧为核心,剖析了 C++ 算法在处理经典问题中的高效应用。通过“移动零”“复写零”和“盛水最多的容器”三个典型例题,深入展示了对撞指针与逆序复写的精妙之处。双指针法以其简洁优雅的逻辑,使得算法在减少时间复杂度的同时保持了高效的空间利用,体现了程序设计中的思维艺术。从逐一移动零元素的位置,到复写零并避免覆盖,再到最大化容器盛水量,每一步分析都着眼于解决问题的本质,精准而不失灵活。文章最后展望了即将展开的快慢指针等高级应用,希望能与读者一同深入探索算法的深邃与美妙,揭示更多编程的无限可能。

半截诗的博客~ 6830
上一篇: 写了3个月React,我学到了什么?
下一篇: 发现数据结构之美-栈
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

趁你还年轻233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值