双指针算法

双指针算法顾名思义就是采用左右指针,对数组、字符串进行查找或排序。常见的采用双指针算法方式有以下几个

从中间向两边进行扩散,两边向中间进行集合。


快速排序

基本思想

  • 找到数组中最中间的数值,以该数值为基点,大于该值则放在右侧,反之,左侧。
  • 然后利用递归的思想再将左序列当成一个完整的序列再进行排序。
  • 同样把序列的右侧也当成一个完整的序列进行排序。
  • 直到数组长度 <= 1,返回该数组。

有三种方法可以实现

  • 借助俩数组空间
  • Lomuto partition scheme
  • Hoare partition scheme

这里主要是使用第三种方法(双指针),其他两种方法可以看这里

https://github.com/Haohao-555/interview/blob/main/7%E6%9C%88/%E7%AC%94%E8%AE%B0.md

思路:以挖萝卜填坑为例子实现该算法

规则:

  • 首先,一连串待排序的数值指的是该排萝卜的大小。

  • 两个工人A、B分别站在并排萝卜的最左侧和最右侧

  • 确定填坑的判断依据

    • 以挖出最左边的萝卜为基准值。
    • A 为 B 填坑的标准是 挖到的萝卜必须比基准值大,才可为 B 填坑
    • B 为 A 填坑,则比基准值小。
  • 两工人挖萝卜的方向,及其萝卜是否符合规则。

    • A :从左到右,并且该萝卜必须在 B 的左侧
    • B:从右到左,并且该萝卜必须在 A 的右侧
  • 谁先开始:

    • 一方坑为空时,另外一方先开始为其填坑。

    • 根据前面几点要求,此时 A 所站位置为坑,B为其填坑。

  • 什么时候结束:

    俩个工人相遇,则结束该次填坑。

    • 并且相遇位置必定为坑。
    • 把一开始挖出来的萝卜给填到该坑上。可以看到以该位置为基准,左侧都小于该值,右侧都大于该值。
    • 到这里,需要以相遇位置,将其分割成左侧和右侧萝卜,再分别完成两侧的萝卜游戏。
    • 已此类推,直到开始填坑前判断起始位大于等于结束位,则说明萝卜已排好序。

游戏开始:

function quicksort(arr, left, right) {let len = arr.length;// 起始位left = typeof left !== 'number' ? 0 : left;// 结束位right = typeof right !== 'number' ? len - 1 : right; // 两者相遇if (left >= right) return// 挖出最左边萝卜let value = arr[left] // 工人 A 所站位置let A = left;// 工人 B 所站位置let B = right;// 两人没有相遇while (A < B) {// 此时 工人 A 位置是一个空坑// B从右往左找比 最左边(value)小的萝卜,并且其位置正在工人 A 的右侧while (B > A && arr[B] >= value) {B--;}// B 找到啦,把该位置的萝卜挖个 工人 A 进行填坑arr[A] = arr[B];// 此时 工人 B 位置是一个空坑// A从左往右找比 最左边(value)大的萝卜,并且其位置正在工人 B 的左侧while (A < B && arr[A] <= value) {A++;}// A 找到啦 该位置的萝卜挖个 工人 B 进行填坑arr[B] = arr[A];// 此时 工人 A 位置是一个空坑// 如果俩工人没有相遇,则再次为对方填坑}/*该次填坑结束,此时 工人A、工人B(A == B)相遇,并且该位置为空,将一开始挖出来的萝卜   (value)放到该位置上此时形成的结果是:相遇位置的左侧都小于 value,右侧都大于 value*/arr[A] = value; // 在相遇位置作为分隔点,将其分割成俩个数组,在进行递归// 左侧萝卜quicksort(arr, left, A);// 右侧萝卜quicksort(arr, A + 1, right);
}
let arr1 = [];
let arr2 = [];for (let i = 0; i < 300000; i++) {let num = Math.floor(Math.random() * (10000 - 1) + 1);arr1.push(num)arr2.push(num)
}
console.time()
quicksort(arr1)
console.timeEnd()
console.log(arr1)console.log("----------------")console.time()
arr2.sort((a, b) => a - b)
console.timeEnd()
console.log(arr2)


最长回文子串

原题

解法:双指针

回文子串分为两种

  • 奇数子串 aba
  • 偶数子串 abba

取中心点向俩边扩散

  • 奇数中心点 左:i 右:i
  • 偶数中心点 左:i 右:i+1
let longestPalindrome = function (s) {let max = "";for (let i = 0; i < s.length; i++) {// 奇数子串helper(i, i);// 偶数子串helper(i, i+1);}function helper(l, r) {// 找左右相同字符串while (l >= 0 && r < s.length && s[l] == s[r]) {l--;r++;}// 找到回文子串后,由于 while 再执行了一轮循环,故需要对指针进行回退,即 (l + 1) (r - 1)const maxStr = s.slice(l + 1, r + 1 - 1);if (maxStr.length > max.length) max = maxStr;}return max;
}let s = "abbaabbaaccaabbaab";
console.log(longestPalindrome(s));

盛最多水的容器


解法:双指针

  • 从两端位置向中间靠拢,计算当前面积。
  • 比较当前两端高度值,高度小的一边向中间靠拢。
  • 当两端重合时,结束,输出最大面积
function test(arr) {let l = 0;let r = arr.length - 1;let max = 0;while(l < r) {let maxArea = (r - l) * Math.min(arr[l], arr[r]);if (maxArea > max) max = maxArea;arr[l] < arr[r] ? l++ : r--;}return max;
}

最接近的三数之和


解法:采用双指针的方式

  • 对数组进行升序排序
  • 遍历数组,从第 i 点开始作为三个值的其中一个,将左指针定位到第 i + 1,右指针定位到 nums.length - 1;
  • 每次遍历,计算当前三者值,与目标值(target)更接近则保存该值
  • 比目标值小,则左指针右移。
  • 比目标值大,则右指针左移。
/*** @param {number[]} nums* @param {number} target* @return {number}*/
var threeSumClosest = function(nums, target) {// 升序排nums.sort((a, b) => a - b);// 假设前三最接近目标值let ans = nums[0] + nums[1] + nums[2];for (let i = 0; i < nums.length; i++) { // 遍历数组let l = i + 1; // 左指针let r = nums.length - 1; // 右指针while(l < r) {// 计算此轮循环的当前值let sum = nums[i] + nums[l] + nums[r];// 比较,谁更接近目标值if (Math.abs(target - sum) < Math.abs(target - ans)) ans = sum;// 比目标值大if (sum > target) r--;// 比目标值小else if (sum < target) l++;// 等于目标值,直接返回else return ans}}return ans;
};

删除数组中重复的数字



解法:双指针fastslow

起始点:俩指针都从数组下标为1开始

结束标志:到达数组尾部

slow 所指位置代表从 0 ~ (slow - 1) 没有重复的数字,slow位置代表当前可能需要被替换

fast 代表下一个数字

/*** @param {number[]} nums* @return {number}*/
var removeDuplicates = function(nums) {let len = nums.length;if (len == 0) return [];let fast = 1;let slow = 1; // 待替换位置while (fast < len) {if (nums[fast] !== nums[fast - 1]) {// 当前 slow 前(包括slow)都不重复nums[slow] = nums[fast];// 指向下一个待替换位置++slow;}// 继续前进++fast;}return slow
};

移除元素



解法:双指针(快慢指针)跟 删除数组中重复的数字类似

var removeElement = function(nums, val) {const n = nums.length;let left = 0;for (let right = 0; right < n; right++) {if (nums[right] !== val) {nums[left] = nums[right];left++;}}return left;
};

搜索插入位置


解法:双指针

var searchInsert = function(nums, target) {const n = nums.length;let left = 0, right = n - 1, ans = n;while (left <= right) {let mid = ((right - left) / 2) + left;if (target <= nums[mid]) {ans = mid;right = mid - 1;} else {left = mid + 1;}}return ans;
};

更新中…

双指针算法(更新中....)相关推荐

  1. 数据结构与算法--更新中...

    本质 : 对数据的查找. 插入和删除 目的: 建立时间复杂度.空间复杂度意识,写出高质量的代码,能够设计基础架构,提升编程技能,训练逻辑思维,积攒人生经验. 以此获得工作回报,实现你的价值,完善你的人 ...

  2. AcWing算法基础课 第一讲小结(持续更新中)

    目录 前言 一.快速排序法及其扩展 快速排序法 介绍 思路 + 步骤 模拟代入 模板 练习 扩展(求第k个数) 思路 代码 二.归并排序法 归并排序 思路 思路 + 步骤 模拟代入 模板 练习 应用( ...

  3. 算法与数据结构模版(AcWing算法基础课笔记,持续更新中)

    AcWing算法基础课笔记 文章目录 AcWing算法基础课笔记 第一章 基础算法 1. 排序 快速排序: 归并排序: 2. 二分 整数二分 浮点数二分 3. 高精度 高精度加法 高精度减法 高精度乘 ...

  4. leetcode贪心算法题集锦(持续更新中)

    leetcode贪心算法题集锦 leetcode贪心算法题集锦(持续更新中).python 和C++编写. 文章目录 leetcode贪心算法题集锦 一.贪心算法 1.盛最多水的容器 2.买股票的最佳 ...

  5. 数据结构与算法-java笔记一 更新中

    数据结构与算法-java笔记一 更新中 数据结构与算法 什么是数据结构.算法 数据结构学了有什么用: 线性结构 数组 特点 应用 链表 存储结构 链表类型 单链表 双向链表 双向循环链表 链表与数组的 ...

  6. 本专栏所有力扣题目的目录链接, 刷算法题目的顺序(由易到难/面试频率)/注意点/技巧, 以及思维导图源文件问题(持续更新中)

    这篇文章为本专栏所有力扣题目提供目录链接, 更加方便读者根据题型或面试频率进行阅读, 此外也会介绍我在刷题过程中总结的刷算法题目的顺序/注意点/技巧, 最后说下文中出现的思维导图源文件的问题 和 打卡 ...

  7. 【更新完毕】《算法竞赛中的初等数论》(ACM / OI / MO)前言、后记、目录索引(十五万字符的数论书)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 <算法竞赛中的初等数论>的全部内容的 Portable Document Format 版 ...

  8. 机器学习算法工程师面试集锦(更新中)

    机器学习算法工程师面试集锦(更新中) 面试问题汇总 常用的损失函数 介绍交叉验证 特征选择方法 机器学习项目的一般步骤 经验风险最小化与结构风险最小化 训练决策树时的参数是什么 在决策树的节点处分割标 ...

  9. 有关树的常见算法汇总【持续更新中】

    关于数据结构中--树的算法汇总[持续更新中] 0.树的顺序和链式存储结构 [完成] 1.树的前序遍历(递归和非递归java实现) [完成] 2.树的中序遍历(递归和非递归java实现) [完成] 3. ...

最新文章

  1. ltrim($str);
  2. 通过lseek产生空洞文件
  3. 委托的BeginInvoke和EndInvoke
  4. cnblogs客户端发贴解析,Post,Get分析
  5. dozer无法映射java8中的LocalDateTime类型的解决方案
  6. python中可变参数*args传入函数时的存储方式为,Python函数可变参数(*args,**kwargs)详解...
  7. masm5安装教程_MASM 6.11的安装与设置
  8. jQuery表单提交
  9. 高速串行收发器的预加重与均衡
  10. C站一名 普通技术博主 的终端与【开端】,因为热爱,所以习惯,2021~2022
  11. OpenContrail 体系
  12. “IT 变革” 云 = 美国道富银行砍掉了850个IT职位
  13. LeetCode 55. 跳跃游戏
  14. peewee和peewee_async常用汇总(持续更新)
  15. 雷电助手连接不到服务器,雷电模拟器无法联网怎么办 雷电模拟器网络异常的解决办法...
  16. 批量(清除)删除Word回车符
  17. 2019计算机电源海关征税,2019年海关税率汇总,海淘常见产品轻松算税费啦~
  18. Udemy上最好的JavaScript课程之一,强烈推荐新手入门学习
  19. .so文件导致的算法运行失败
  20. 精益生产方式有哪些?精益生产方式的核心是什么?

热门文章

  1. js压缩、混淆和加密
  2. Linux中的18个tar命令
  3. Long-Short Term Memory(长短时记忆模型)
  4. 人生第一场CTF的解题报告(部分)
  5. JAVA 生成数据表图标LOGO二维码
  6. RK3399 GPT分区
  7. 学习笔记:隋唐人的日常生活——隋唐的城市生活(上)
  8. 计算机cpu的发展历程,CPU发展历程
  9. FusionCharts用法总结
  10. 会计转java6_会计转行从事 IT,如何在一年时间内全职学习?