• 算法思维 ---- 双指针法


    双指针

    双指针可分为三类:

    • 左右指针
    • 快慢指针
    • 滑动窗口

    其中,滑动窗口 已单独写了一篇随笔,可跳转查看。

    在快慢指针中,又有一类典型算法,叫 Floyd's cycle-finding algorithm,其又名 Floyd's Hare and Tortoise Algorithm

    在这里,我们主要谈论 左右指针快慢指针。左右指针 主要应用在数组中,快慢指针 主要应用在数组和链表中。

    左右指针

    见名知意,左右指针就是指针在数组的两端向中间靠拢,典型的二分法使用的就是此类指针。

    二分查找

    const binarySearch = (nums, target) => {
      let left = 0, right = nums.length - 1;
      while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (nums[mid] === target) return mid;
        else if (nums[mid] < target) left = mid + 1;
        else if (nums[mid] > target) right = mid - 1;
      }
      return -1;
    }
    

    反转数组

    let reverse = (nums) => {
      let left = 0, right = nums.length - 1;
    
      while (left <= right) {
        [nums[left], nums[right]] = [nums[right], nums[left]];
        left++;
        right--;
      }
    }
    

    快慢指针

    快慢指针中的一类典型算法已经写了随笔,可跳转看看。Floyd's cycle-finding Algorithm

    快慢指针,其实就是有 fastslow 指针,它们以不同的速度前进,或者 fast 先行,满足一定条件后,slow 再前行。

    链表中点

    fast 指针一次两步,slow 指针一次一步,当 fast 指针到达链表尾时,slow 指针就处于链表的中间位置,或者是中间偏右的位置(偶数个结点)。

    如果是找中间数或者删除中间结点时,我们可以加多一个变量来记录 slow 的上一步的结点,以便操作。

    while (fast !== null && fast.next !== null) {
      fast = fast.next.next;
      slow = slow.next;
    }
    

    寻找链表的倒数第k个元素

    这里是让 fast 指针先行 k 步,然后两指针同时同步前进。当 fast 指针到达指针末尾时,slow 指针就是倒数第k个元素了。

    while (k-- > 0) {
      fast = fast.next;
    }
    
    while (fast !== null) {
      fast = fast.next;
      slow = slow.next;
    }
    // 此时 slow 就是倒数第k个元素
    

    移除元素

    我们让 fast 先行,如果找到不是指定移除的元素的元素,我们就让它替换到 slow 的位置,然后 slow 指针前进一步。

    当操作完成后,slow 指针的位置就是操作后的数组的长度。下面算法主要展示的是移除数组元素的,移除链表元素也是同样的操作,不过最后的 slow 指针指向的结点的next域需要置空。

    用快慢指针就可以在原数组或链表的基础上进行移除元素,当然这要看实际需求,如果不能操作原数据,则需要消耗O(n)空间复杂度。

    let slow = 0, fast = 0;
    while (fast < nums.length) {
      if (nums[fast] != val) {
        nums[slow++] = nums[fast];
      }
      fast++;
    }
    

    总结

    左右指针快慢指针 就是这么简单的操作,复杂的还是 滑动窗口,不过其也是有套路可循的。

    算法,最重要的还是其背后的思维。把算法思维转化为代码也是很重要的。

    还需很努力,很有很多算法没有掌握,输入消化吸收后也要对应输出。

  • 相关阅读:
    mysql常用技能分享
    php生成器使用总结
    MySQL索引使用方法和性能优化
    servlet相关
    UML图
    How Tomcat Works
    字符串编码
    高效工作
    php 设计模式总结
    python之装饰器
  • 原文地址:https://www.cnblogs.com/AuKing/p/14040594.html
Copyright © 2020-2023  润新知