编程题-链表与双指针

总结:链表相关的题目大部分可以用双指针解决。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 (step<k-1 && p1)
        {
            step++;
            p1 = p1->next;
        }

        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步,相遇点即为入环起点。

附加 3)判断环的长度:其中一个指针不动,另外一个一步一步走,再次相遇时走的步数即为环的长度。

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;
    }
};

4、回文链表[4] 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        /*
        1. 找到链表中点(n+1)/2, p2
        2. p2反转
        3. 顺序比较p1和p2
        4. 反转p2,恢复原样
        */
        ListNode* p1 = head, *p2 = head;
        while (p2)
        {
            p2 = p2->next;
            if (p2)
            {
                p2 = p2->next;
                p1 = p1->next;
            }    
        }
        p2 = reverseList(p1);
        ListNode* p = p1;
        p1 = head;
        bool flag = true; 
        while (p1&&p2)
        {
            if (p1->val != p2->val)
                flag = false;
            p1 = p1->next;
            p2 = p2->next;
        }
        p2 = reverseList(p);
        return flag;
    }

   ListNode* reverseList(ListNode* head) {
        if (head==NULL)
            return head;
        ListNode* newlist = head;
        head = head->next;
        newlist->next = NULL;
        while (head)
        {
            ListNode* tmp = head->next;
            head->next = newlist;
            newlist = head;
            head = tmp;
        }
        return newlist;
    }
};

[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/

[4]https://leetcode-cn.com/problems/palindrome-linked-list-lcci/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值