编程题-链表与双指针

总结:链表相关的题目大部分可以用双指针解决。i.e.,找链表倒数第k个节点,找链表中间1/2节点,检测链表是否存在环。快慢指针

1、找链表中倒数第k个节点[1]

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

/*双指针 

1)p1比p2先行k-1步,当p1到达最后一个节点,p2指向倒数第k个节点

2)p1比p2先行k步,当p1到达最后终点(NULL),p2指向倒数第k个节点

*/

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) {
        /*双指针
        p1比p2先行k-1步
        */
        ListNode* p1 = head;
        ListNode* p2 = head;
        //p1先行k-1步
        int step = 0;
        while (stepnext;
        }

        if (!p1) return NULL;

        while (p1->next)
        {
            p1 = p1->next;
            p2 = p2->next;
        }
        return p2;
    }
};

2、链表的中间节点[2]

 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

思路::快慢指针,快指针p2一次走2步,慢指针p1一次走1步。

需要特殊处理的是:偶数节点是输出第二个中间节点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        if (!head)
            return head;
        ListNode* p1 = head, *p2=head;
        
        while (p2->next)
        {
            p1 = p1->next;
            p2 = p2->next;
            if (p2->next)
                p2 = p2->next;
        }
        return p1;

    }
};

3、环形链表[3]

判断链表是否有环,若存在环,找出入环起点。

 思路:

1)确定是否有环,快慢指针,快指针*fast每次移动2步(或多步),慢指针*slow每次移动1步,若存在环,二者一定会在环上相遇,且相遇时慢指针尚未走完1圈(证明见leetcode官方题解);否则无环。

2)确认有环(快慢指针相遇后),将其中一个移到链表起点head,而后二者每次均移动1步,相遇点即为入环起点。

c++代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head)
            return head;
        ListNode *fast = head, *slow=head;
        while (fast->next&&fast->next->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) //有环,确定入环起点
            {
                fast = head;
                while (fast != slow)
                {
                    fast = fast->next;
                    slow = slow->next;
                }
                return slow;
            }
        }
        return NULL;
    }
};

[1]https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/

[2]https://leetcode-cn.com/problems/middle-of-the-linked-list/

[3]https://leetcode-cn.com/problems/linked-list-cycle-ii/

你可能感兴趣的:(编程,双指针,链表)