美文网首页
快慢指针的应用

快慢指针的应用

作者: 不锈钢_231d | 来源:发表于2020-04-22 11:42 被阅读0次

---

最近在刷LeetCode时,发现快慢指针在链表和查找算法中应用非常广泛,对于很多即将面试或者学习算法的同学们,熟练运用双指针也有助于对线性表更好的理解。

快慢指针,是双指针的一种应用方式。双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。基本思想是使用两个指针以不同的速度在数组或链表中移动。 

换言之, 凡事需要查找的结果节点位置和链表位置相对位置明确,有属于链表节点查找问题,此方法非常有用。

快慢指针主要有三大类应用场景:

-  **找到链表的中点。**

-  **判断链表中是否存在环。**

-  **查找或删除链表(线性表)的某个节点。**

---

## 找到链表的中点。

比如有这样一道题"如何访问链表中间节点?"

简单地实现方法:遍历一遍整个的链表,然后计算出链表的长度,进而遍历第二遍找出中间位置的数据。

如果要求只能遍历一次链表,那又当如何解决?

可以采取建立两个指针,一个指针一次遍历两个节点(快指针),另一个节点一次遍历一个节点(慢指针),当快指针遍历到空节点时,则慢指针指向的位置为链表的中间位置。

_LeetCode 876. 链表的中间结点一个带有头结点head的非空单链表,返回链表的中间结点。 若该链表有两个中间结点,则返回第二个中间结点。_

例1:输入:[1,2,3,4,5] 输出:此列表中的结点为3 (序列化形式:[3,4,5]) 返回的结点为3。 (检测系统序列化遍历该节点 [3,4,5]) 注意,我们返回了的ListNode类型的数组ans,满足: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.(意思是会最后会对结果middle以及其后的节点作校验)

例2:输入:[1,2,3,4,5,6] 输出:此列表中的结点 4 (检测系统序列化遍历该节点:[4,5,6]) 因为该列表有两个中间结点,值分别为3和4,最终返回第二个结点。 

 提示:链表结点数介于1到100之间。

代码如下:

```C

struct ListNode* middleNode(struct ListNode* head){

    struct ListNode* pFast = head;

    struct ListNode* pSlow = head;

    //慢指针每次移动一步,快指针每次移动两步,直到快指针到达边界

    while((pFast != NULL)&&(pFast->next != NULL))

    {

        pSlow = pSlow->next;

        pFast = pFast->next->next;

    }

    return pSlow;

}

```

---

## 判断链表中是否存在环?

![判断链表中是否存在环](/post/绘图1.png)

快指针每次遍历会比慢指针多一个元素,如果链表已经成环,无论快指针和慢指针之间相隔多少个节点,快指针总是能够追上慢指针(条件是快指针和慢指针指向同一个节点),这个时候就可以判断链表已经成环;否则快指针进行一轮遍历之后就会跳出循环,永远不可能和慢指针“重合”。

代码如下:

``` C

bool hasCycle(struct ListNode *head) {

    if (!head) return false;

    struct ListNode* pFast = head;

    struct ListNode* pSlow = head;

    while (pFast && pFast->next)

    {

        pFast = pFast->next->next;        

        pSlow = pSlow->next;

        if (pSlow == pFast)      

        {

            return true;

        }

    }

    return false;

}

```

---

## 删除线性表中的倒数第N个节点呢?

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

![](/post/删除倒数第N个.png)

从头结点开始,快指针FIRST从N+1开始移动,慢指针SECOND指向头结点。

FIRST和SECOND相间隔N个节点,FIRST和SECOND每次移动一步。

当FIRST指向尾节点时,循环结束, SECOND的next节点即为要被删除的节点。

将SECOND的next指向被删除节点的后一个节点,即完成删除操作。

代码如下

``` C

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){

        if (head == NULL || head->next == NULL) return NULL;

        int i;

        struct ListNode* pFast = head;

        struct ListNode* pSlow = head;        

        for (i = 0; i < n; i++)

        {

                pFast = pFast->next;             

        }

        if (pFast == NULL) return head->next;

        while (pFast->next)

        {

                pSlow = pSlow->next;

                pFast = pFast->next;

        }

        pSlow->next = pSlow->next->next;

        return head;

}

```

---

## 删除有序链表的重复元素

快慢指针还有一种应用,就是删除线性表中某些元素,在不额外增加空间复杂度的基础上(原位计算),实现数组或链表的有序化

比如给你一个字符串 S,请你删去其中的所有元音字母( 'a','e','i','o','u'),并返回这个新字符串。

>示例 1:

输入:"leetcodeisacommunityforcoders"

输出:"ltcdscmmntyfrcdrs"

示例 2:

输入:"aeiou"

输出:""

提示:

S 仅由小写英文字母组成。

1 <= S.length <= 1000

可以按照如下方法实现:由于字符串仅由英文字母构成,其ASCII码值从97到123构成,

1 可以构造一个128位的HASHTABLE,表中命中元音字母的元素记为1,否则为0

2 快慢指针同时从0开始,pFast一步一步向前遍历整个HASHTABLE,不受任何影响,pSlow作为输出,在只有HASHTABLE未命中时才向前走

3 将pFast的内容拷贝给pSlow,最终实现pSlow的输出。

代码如下:

``` C {.line-numbers}

char * removeVowels(char * S){

    char  HASH_TABLE[128] = {0};

    char* pFast = S;

    char* pSlow = S;

    const char Vowel[] = {'a', 'e', 'i','o', 'u', '\0'};

    const char* pTemp = Vowel;

    while (*pTemp)

    {

        HASH_TABLE[*pTemp] = 1;

        ++pTemp;

    }

    while(*pFast)

    {

        *pSlow = *pFast;    

        if ( 0 == HASH_TABLE[*(pFast++)] )

        {

            pSlow++;

        }

    }

    *pSlow = '\0';

    return S;

}

```

---

相关文章

  • 快慢指针的应用

    快慢指针 快慢指针中的快慢指的是移动的步长,快慢分别指的是快指针每次移动两步,满指针每次移动一步 快慢指针的应用 ...

  • 快慢指针的应用

    快慢指针的快慢主要是指在遍历链表过程中指针移动速度的快慢。比如遍历单链表,我们可以让指针每次移动一个节点,也可以让...

  • 快慢指针的应用

    --- 最近在刷LeetCode时,发现快慢指针在链表和查找算法中应用非常广泛,对于很多即将面试或者学习算法的同学...

  • 快慢指针的应用

    什么是快慢指针:快慢指针是链表操作中的常用操作,最经典的应用是判断单链表中是否有环。 判断单链表是否存在环 两个指...

  • 快慢指针的算法应用

    快慢指针主要解决的问题: 寻找/删除第K个节点; 有关链表环问题解法:寻找/删除第K个节点。 问题一: 给定任意一...

  • 快慢指针总结

    快慢指针 所谓「快慢指针」是指设定两个指针,其中快的指针的移动速度是慢的指针的移动速度的两倍;“快慢指针”方法主要...

  • leetcode 中快慢指针的应用

    快慢指针的在leetcode的问题中有很多应用,例如通过一次遍历找到链表的中间节点。 这里要介绍的是作为哨兵,应用...

  • leetcode第142题:环形链表II [中等]

    题目描述 考点 链表 双指针(快慢指针) 解题思路 设置快慢指针slow, fast; 慢指针slow每次移动一个...

  • 快慢指针

    快慢指针即我们有两个及以上的指针,我们可以通过控制其步长去实现某种行为。 下图中自定义的名词解释如下: 目标节点:...

  • 快慢指针

    找出单向链表中倒数第 k 个节点。返回该节点的值普通解法时间复杂度2N 用快慢指针只用循环一遍N就行了

网友评论

      本文标题:快慢指针的应用

      本文链接:https://www.haomeiwen.com/subject/qxybzxtx.html