【数据结构】——利用快慢指针解决的链表问题

说到数据结构中的单链表,我们可以想到很多关于此结构的问题,这篇文章主要总结了几个关于用同一种方式——快慢指针来解决的问题~
一、第一题——返回链表的中间结点
题目要求:
在这里插入图片描述
解题思路:

& 利用快慢指针,快指针每次走两步,慢指针每次走一步
& 最后返回慢指针
& 注意,循环条件时,fast != NULL && fast->next != NULL,因为存在结点数目是奇数还是偶数的情况

代码实现:

ListNode* middleNode(ListNode* head) {
       ListNode* fast = head;
       ListNode* slow = head;
       while(fast != NULL && fast->next != NULL)
       {
           fast = fast->next->next;
           slow = slow->next;
       }
       return slow;
}

二、第二题——返回链表中的倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点

解题思路:
& 和上一题的思想还是一样利用快慢指针来求解
& 特殊情况考虑:当结点为空或者k<0的时候,都应该返回空
& 首先让快指针先走k-1步
& 然后同步走
& 最后返回满指正的值

代码实现:

ListNode*
FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead == 0 || k<=0)
            return NULL;
        ListNode* fast = pListHead;
        ListNode* slow = pListHead;
        for(int i = 0;i<k-1;i++)
        {
            if(fast->next != NULL)
            {
               fast = fast->next;
            }
            else  return NULL;     
        }
        while(fast -> next != NULL)
        {
           fast = fast ->next;
           slow = slow->next;
        }
        return slow;
}

三、第三题——判断是否为回文结构
在这里插入图片描述
解题思路:
& 利用快慢指针,第一步设置一个快指针和慢指针
& 快指针一次走两步,慢指针一次走一步,当快指针下一步为null的时候说明慢指针已经走了一半,这样就可以找到中间结点
& 再反转中间链表后面的指针
& 再从头到尾向中间扫描,对比每个元素是否相等,如果都相等就是回文数,否则不是回文数

代码实现:

bool
chkPalindrome(ListNode* A) {
        if(A == NULL)
        return false;
    else if(A->next == NULL)
        return true;
    //快慢指针找出中间结点
    ListNode* fast = A;
    ListNode* slow = A;
    while(fast != NULL && fast->next!= NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    //反转
    ListNode* p = slow->next;
    ListNode* p1 = p->next;
    while(p != NULL)
    {
        p->next = slow;
        slow = p;
        p = p1;
        p1 = p1->next;
    }
    //比较
    while(A != slow)
    {
        if((A->val) != (slow->val))
        {
           return false;
        }
        else 
        {
           if(A->next == slow)
           {
              return true;
           }
           A = A->next;
           slow = slow->next;
        }
    }
    return true;
}

四、第四题——判断链表中是否有环

在这里插入图片描述
解题思路:
& 采用快慢指针的方式,想象成两个运动员,如果相遇了则表示有环存在

代码实现:

bool hasCycle(ListNode *head) {
    if(head == NULL)
        return NULL;
    ListNode* fast = head;
    ListNode* slow = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
            return true;
    }
    return false;
}

五、第五题——返回链表入环的第一个结点
在这里插入图片描述
解题思路:
& 注意!上一题我们的求解过程中,环的相遇点不一定是环的起点
& 根据规律,我们可以用数学公式推导出来,非环部分的长度+环起点到相遇点之间的长度就是环的整数倍。这意味着两个指针从相遇点再走x距离就刚刚走了很多圈,也就意味着如果从相遇点再走x就到了环的起点
& 怎么才能走x步呢?——让一个指针从头开始走,另一个指针从相遇点开始走,等两个指针相遇那就走了x步,此时就是环的起点

代码实现:

ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
    ListNode* slow = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            fast = head;
            while(fast != slow)
            {
                fast = fast->next;
                slow = slow->next;
            }
            return fast;
        }
    }
    return NULL;
}
发布了62 篇原创文章 · 获赞 7 · 访问量 2585

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104315713