前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >算法一招鲜——双指针问题

算法一招鲜——双指针问题

作者头像
用户1687375
发布于 2019-07-30 08:40:59
发布于 2019-07-30 08:40:59
91500
代码可运行
举报
文章被收录于专栏:较真的前端较真的前端
运行总次数:0
代码可运行

本文首发于知乎专栏——前端面试题汇总,大家可以通过文章底部的阅读原来来访问原文地址

什么是双指针(对撞指针、快慢指针)

双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。

换言之,双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。

LeetCode题库中,关于双指针的问题还是挺多的。双指针

截图来之LeetCode中文官网

用法

对撞指针

对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。

对撞数组适用于有序数组,也就是说当你遇到题目给定有序数组时,应该第一时间想到用对撞指针解题

伪代码大致如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function fn (list) {
  var left = 0;
  var right = list.length - 1;

  //遍历数组
  while (left <= right) {
    left++;
    // 一些条件判断 和处理
    ... ...
    right--;
  }
}

举个LeetCode上的例子:

LeetCode 881救生艇问题为例

由于本题只要求计算出最小船数,所以原数组是否被改变,和元素索引位置都不在考虑位置,所以可以先对于给定数组进行排序,再从数组两侧向中间遍历。所以解题思路如下:

  1. 对给定数组进行升序排序
  2. 初始化左右指针
  3. 每次都用一个”最重的“和一个”最轻的“进行配对,如果二人重量小于Limit,则此时的”最轻的“上船,即(left++)。不管”最轻的“是否上船,”最重的“都要上船,即(right--)并且所需船数量加一,即(num++

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var numRescueBoats = function(people, limit) {
  people.sort((a, b) => (a - b));
  var num = 0
  let left = 0
  let right = people.length - 1
  while (left <= right) {
    if ((people[left] + people[right]) <= limit) {
      left++
    }
    right--
    num++
  }
  return num
};

快慢指针

快慢指针也是双指针,但是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)慢指针(slow),两个指针以不同的策略移动,直到两个指针的值相等(或其他特殊条件)为止,如fast每次增长两个,slow每次增长一个。

以LeetCode 141.环形链表为例,,判断给定链表中是否存在环,可以定义快慢两个指针,快指针每次增长一个,而慢指针每次增长两个,最后两个指针指向节点的值相等,则说明有环。就好像一个环形跑道上有一快一慢两个运动员赛跑,如果时间足够长,跑地快的运动员一定会赶上慢的运动员。

解题代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
  if (head === null || head.next === null) {
    return false
  }

  let slow = head
  let fast = head.next

  while (slow !== fast) {
    if (fast === null || fast.next === null) {
      return false
    }
    slow = slow.next
    fast = fast.next.next
  }
  return true
};

再比如LeetCode 26 删除排序数组中的重复项,这里还是定义快慢两个指针。快指针每次增长一个,慢指针只有当快慢指针上的值不同时,才增长一个(由于是有序数组,快慢指针值不等说明找到了新值)。

真实代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var removeDuplicates = function (nums) {
  if (nums.length === 0) {
    return 0;
  }
  let slow = 0;
  for (let fast = 0; fast < nums.length; fast++) {
    if (nums[fast] !== nums[slow]) {
      slow++;
      nums[slow] = nums[fast];
    }
  }
  return slow + 1;
};

总结

当遇到有序数组时,应该优先想到双指针来解决问题,因两个指针的同时遍历会减少空间复杂度和时间复杂度。

相关题目

LeetCode.141.环形链表 LeetCode.026.删除数组中重复的项 LeetCode.881.救生艇

参考文献

  • 《LeetBook》双指针
  • 【算法总结--数组相关】双指针法的常见应用。
  • 1.4.2 双指针技巧(二)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 较真的前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
文心一言 VS 讯飞星火 VS chatgpt (30)-- 算法导论5.2 2题
我们可以先计算出在HIRE-ASSISTANT中,雇佣一个应聘者的概率为3/4,然后计算出雇佣两次应聘者的概率为3/4 3/4 2。
福大大架构师每日一题
2023/06/03
1910
文心一言 VS 讯飞星火 VS chatgpt (26)-- 算法导论5.1 1题
假设在过程 HIRE-ASSISTANT 的第 4 行中,我们总能决定哪一个应聘者最佳。则意味着我们知道应聘者排名的全部次序。
福大大架构师每日一题
2023/05/30
1820
文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题
这是一个典型的概率问题。首先,我们可以通过简单的计算来理解问题的背景。假设我们有n个球和n个箱子,每个球被投人到箱子里的概率是相等的,即每个箱子有1/n的概率被选中。
福大大架构师每日一题
2023/06/21
2190
文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题
文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
在大小为n的集合中,一个k字符串构成一个k排列的概率是1/k!,这是由于排列的总数是k!,而每个字符串被选中的概率是相等的,因此每个字符串构成一个排列的概率是1/k!。
福大大架构师每日一题
2023/06/21
2230
文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
文心一言 VS 讯飞星火 VS chatgpt (31)-- 算法导论5.2 3题
指示器随机变量是一种特殊的随机变量,它只有两个取值:0和1。通常用I来表示指示器随机变量,它的取值为1表示事件发生,取值为0表示事件未发生。在掷骰子的例子中,我们可以将指示器随机变量定义为:
福大大架构师每日一题
2023/06/04
4100
文心一言 VS 讯飞星火 VS chatgpt (33)-- 算法导论5.2 5题
假设A的元素构成(1, 2, ..., n)上的一个均匀随机排列,我们可以使用指示器随机变量来计算其中逆序对的数目期望。
福大大架构师每日一题
2023/06/06
1640
文心一言 VS 讯飞星火 VS chatgpt (35)-- 算法导论5.3 5题
在过程PERMUTE-BY-SORTING中,对于输入数组P中的每个元素,其出现次数为1,因此对于每个元素,在排序后的数组中,它出现的位置是唯一的。
福大大架构师每日一题
2023/06/09
2580
文心一言 VS 讯飞星火 VS chatgpt (35)-- 算法导论5.3 5题
文心一言 VS 讯飞星火 VS chatgpt (32)-- 算法导论5.2 4题
根据指示器随机变量的定义,I(i)表示第i位顾客是否拿到了自己的帽子,其值为1表示拿到,0表示未拿到。
福大大架构师每日一题
2023/06/05
2210
文心一言 VS 讯飞星火 VS chatgpt (34)-- 算法导论5.3 1题
为了解决Marceau教授的质疑,我们需要重新设计过程RANDOMIZE-IN-PLACE,以确保在第一次选择之前循环不变式为真。为了达到这个目的,我们可以对过程进行以下修改:
福大大架构师每日一题
2023/06/09
5160
文心一言 VS 讯飞星火 VS chatgpt (34)-- 算法导论5.3 1题
文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
为了解决这个问题,我们需要先计算出所有可能的生日组合数,然后计算出其中生日相同的组合数。
福大大架构师每日一题
2023/06/21
1910
文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题
首先,我们需要实现一个函数来找到数组的中位数。然后,我们需要实现一个函数来根据中位数对数组进行划分。最后,我们需要计算划分比例的概率。
福大大架构师每日一题
2023/08/29
1710
文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题
文心一言 VS 讯飞星火 VS chatgpt (79)-- 算法导论7.4 4题
首先,为了证明RANDOMIZED-QUICKSORT的期望运行时间是Ω(nlg n),我们需要证明在最坏的情况下,该算法的运行时间是O(nlg n)。然后,我们需要证明在最坏的情况下,算法的期望运行时间是Ω(nlg n)。
福大大架构师每日一题
2023/08/29
3140
文心一言 VS 讯飞星火 VS chatgpt (79)-- 算法导论7.4 4题
文心一言 VS 讯飞星火 VS chatgpt (134)-- 算法导论11.2 6题
在这个问题中,我们需要使用 Go 语言在一个大小为 m 且通过链接法解决冲突的散列表中,从 n 个关键字中均匀随机地选择一个元素。为了达到 O(L·(1+1/a)) 的期望时间复杂度,我们需要考虑以下几个步骤:
福大大架构师每日一题
2023/11/14
1870
文心一言 VS 讯飞星火 VS chatgpt (134)-- 算法导论11.2 6题
文心一言 VS 讯飞星火 VS chatgpt (95)-- 算法导论9.2 4题
首先,让我们澄清一下 "RANDOMIZED-SELECT" 这个术语。我猜您可能指的是随机化算法,该算法用于在最坏情况下以O(n)时间复杂度找到一个无序数组的最小元素。在这种情况下,我们可以使用随机化算法来找到一个导致最坏情况发生的划分序列。
福大大架构师每日一题
2023/09/19
2050
文心一言 VS 讯飞星火 VS chatgpt (95)-- 算法导论9.2 4题
文心一言 VS 讯飞星火 VS chatgpt (28)-- 算法导论5.1 3题
可以使用贝叶斯公式来计算无偏的结果。假设我们进行了n次试验,其中BIASED-RANDOM以概率p输出1,以概率1-p输出0。设N0为输出0的次数,N1为输出1的次数,则有N0+N1=n。根据贝叶斯公式,可以得到:
福大大架构师每日一题
2023/06/01
1700
文心一言 VS 讯飞星火 VS chatgpt (72)-- 算法导论7.1 3题
首先,我们需要明确PARTITION函数的具体定义。PARTITION函数通常用于快速排序算法中,它将一个数组分为两个子数组,使得一个子数组的所有元素都小于另一个子数组的所有元素。
福大大架构师每日一题
2023/08/29
2360
文心一言 VS 讯飞星火 VS chatgpt (72)-- 算法导论7.1 3题
文心一言 VS 讯飞星火 VS chatgpt (43)-- 算法导论5.4 7题
在 n 次硬币的公平抛掷中,每个硬币正、反面朝上的概率均为 1/2。让我们考虑一个事件 A,其表示在 n 次抛掷中不出现比连续 lgn 更长的连续正面特征序列。事件的 A 对立事件 B 由出现比连续 lgn 更长的连续正面特征序列组成。
福大大架构师每日一题
2023/07/08
2770
文心一言 VS 讯飞星火 VS chatgpt (43)-- 算法导论5.4 7题
文心一言 VS 讯飞星火 VS chatgpt (39)-- 算法导论5.4 3题
在生日悖论的分析中,要求各人生日彼此独立是非常重要的。这是因为,如果各人生日不是独立的,而是存在一定的相关性,那么就会影响到概率的计算,从而影响到生日悖论的分析结果。
福大大架构师每日一题
2023/06/21
1750
文心一言 VS 讯飞星火 VS chatgpt (39)-- 算法导论5.4 3题
文心一言 VS 讯飞星火 VS chatgpt (78)-- 算法导论7.4 2题
快速排序是一种分治算法,它将一个数组分成两个子数组,然后对这两个子数组分别进行排序。在最好情况下,每次划分都能将数组等分,即每次划分后得到的两个子数组的长度相等。
福大大架构师每日一题
2023/08/29
1790
文心一言 VS 讯飞星火 VS chatgpt (78)-- 算法导论7.4 2题
文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题
这是一个典型的鸽巢原理(Pigeonhole Principle)问题。假设每次投球时,每个箱子有1/b的概率被选中。我们设投球次数为x。
福大大架构师每日一题
2023/06/21
1530
文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题
推荐阅读
文心一言 VS 讯飞星火 VS chatgpt (30)-- 算法导论5.2 2题
1910
文心一言 VS 讯飞星火 VS chatgpt (26)-- 算法导论5.1 1题
1820
文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题
2190
文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
2230
文心一言 VS 讯飞星火 VS chatgpt (31)-- 算法导论5.2 3题
4100
文心一言 VS 讯飞星火 VS chatgpt (33)-- 算法导论5.2 5题
1640
文心一言 VS 讯飞星火 VS chatgpt (35)-- 算法导论5.3 5题
2580
文心一言 VS 讯飞星火 VS chatgpt (32)-- 算法导论5.2 4题
2210
文心一言 VS 讯飞星火 VS chatgpt (34)-- 算法导论5.3 1题
5160
文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
1910
文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题
1710
文心一言 VS 讯飞星火 VS chatgpt (79)-- 算法导论7.4 4题
3140
文心一言 VS 讯飞星火 VS chatgpt (134)-- 算法导论11.2 6题
1870
文心一言 VS 讯飞星火 VS chatgpt (95)-- 算法导论9.2 4题
2050
文心一言 VS 讯飞星火 VS chatgpt (28)-- 算法导论5.1 3题
1700
文心一言 VS 讯飞星火 VS chatgpt (72)-- 算法导论7.1 3题
2360
文心一言 VS 讯飞星火 VS chatgpt (43)-- 算法导论5.4 7题
2770
文心一言 VS 讯飞星火 VS chatgpt (39)-- 算法导论5.4 3题
1750
文心一言 VS 讯飞星火 VS chatgpt (78)-- 算法导论7.4 2题
1790
文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题
1530
相关推荐
文心一言 VS 讯飞星火 VS chatgpt (30)-- 算法导论5.2 2题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档