数据结构-双指针算法

189 阅读3分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

双指针算法

介绍

双指针算法,依名知意。就是会出现两个指针,但是是在什么情况下出现?又是是如何作用?该如何执行的呢?

1.应用场景

双指针算法的应用场景一般出现在 有序数组 或者 链表,且需要进行遍历的过程。所以我们只要遇到这两种场景,就要立刻第一反应 可能会用到双指针算法。

2.双指针算法分类

双指针算法分类有两种,一种是 快慢指针,一种是 对撞指针。这两种经典且应用场景广泛的指针!

  • 快慢指针

    两个指针 指向同一方向,一个指针在前面,一个指针在后边,根据相关的条件,快指针走得快,慢指针走的慢,直到满足条件或者快指针指向null 或者是 走到结尾 。使用场景:

  • 对撞指针 两个指针 分别指向最左端和最右端,然后找到目标所在的值或下标,动态的移动左右两侧指针,来以此慢慢靠近我们所需的目标值或下标。使用场景:

    • 有序数组的两个数之和 167题

    • 验证是否是回文串 125题

题目

  1. 删除有序数组中的重复项-26

    给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成

  2. 环形链表-141

    给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。如果链表中存在环,则返回 true 。 否则,返回 false

  3. 两数之和 II - 输入有序数组-167

    给定一个已按照 非递减顺序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素

  4. 验证回文串-125

    给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写

代码

  • 快慢指针 26题,80题

    • 有序数组的去重

      // 快慢指针
         const removeDuplicates = (nums) => {
           let i = 0 // 慢指针
           for (let j = 1; j < nums.length; j++) {
             if (nums[j] != nums[i]) {
               i++
               nums[i] = nums[j]
             }
           }
           return i + 1
         }
      
      // 常规方式
          const removeDuplicates = (nums) => {
            for (let i = 0; i < nums.length; ) {
              if (nums.indexOf(nums[i]) !== i) {
                nums.splice(i, 1)
              } else {
                i++
              }
            }
            return nums // 这里返回的是去重后的数组
            // return nums.length // 这里返回的是去重后的数组长度
          }
      
    • 链表是否有环 141题

          const hasCycle = (head) => {
            if (head == null || head.next == null) {
              return false
            }
            var slow = head.next
            var fast = head.next.next
            while (slow !== fast) {
              if (fast == null || fast.next == null) {
                return false
              }
              slow = slow.next
              fast = fast.next.next
            }
            return true
          }
      
  • 对撞指针

    • 有序数组的两个数之和 167题

          const twoSum = (numbers, target) => {
              const numbersLength = numbers.length
              let left = 0
              let right = numbersLength - 1
              while (left < right) {
                  const ans = numbers[left] + numbers[right]
                  if (ans === target) return [left + 1, right + 1]
                  if (ans < target) left++
                  else right--
              }
              return [-1, -1]
          }
      
    • 验证是否是回文串 125题

          const isPalindrome = (s) => {
              // const str = s.replace(/[^\w]/g, '').replace(/_/g, '').toLowerCase()
              const str = s.replace(/[^a-zA-Z0-9]/g, '').toLocaleLowerCase()
              const strArr = str.split('')
              let i = 0
              let j = strArr.length - 1
              while (i < j) {
                  if (strArr[i] !== strArr[j]) {
                      return false
                  }
                  i++
                  j--
              }
              return true
          }
      

总结

双指针算法 作为 数据结构的 基础算法之一,学习它对于帮助打开后续的其他数据结构算法,提升思路的灵活度还是很重要的!