算法总结之常见链表题目

212 阅读2分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

常用方法

  1. 画图理解链表题目
  2. 善用双指针
  3. 设置虚拟头结点解决删除head节点的问题

双指针相关题目

  1. 倒数第k个节点相关、取得/删除倒数第k个节点、旋转链表
  2. 判断链表是否有环
  3. 两链表公共节点

题目解法记录

LeetCode 160 两链表公共节点

普通思路

分别遍历两链表计算长度m、n,长的链表先走m-n步,然后一起走,并比较是否相等

/*
 * @lc app=leetcode id=160 lang=cpp
 *
 * [160] Intersection of Two Linked Lists
 */
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p = headA;
        ListNode *q = headB;

        int i = 0;
        int j = 0;
        while (p!= nullptr)
        {
            p = p->next;
            i++;
        }
        while (q != nullptr)
        {
            q = q->next;
            j++;
        }
        p = headA;
        q = headB;
        while (i > j)
        {
            p = p->next;
            i--;
        }
        while (i < j)
        {
            q = q->next;
            j--;
        }
        while (p != nullptr && q != nullptr)
        {
            if (p == q)
            {
                return p;
            }
            p = p->next;
            q = q->next;
        }
        return nullptr;
    }
};

双指针思路

使用两个指针遍历两链表,当a链表走到头时,开始转到b链表的头,b链表同理,两指针相等时就取到了共同节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *a,*b;
        a = headA;
        b = headB;
        while(a != b){
            if(!a) a = headB;
            else a = a->next;
            if(!b) b = headA;
            else b = b->next;
        }
        return a;
    }
};

LeetCode 142 确定有环链表的节点

算法

  1. 使用快慢指针往前走,直到快指针和慢指针相遇
  2. 然后使用一个指针从头走,慢指针继续走,两指针相遇,则为第一个环节点

原理

  • 首先分析快慢指针相遇时走过的路程,设起点为a,第一个环节点为b,相遇点为c,a->b=x
  • 设慢指针走到b点时,快指针走到c1,则此时c1->b长度等于b->c,设为y,此时慢指针走了x步,则快指针走了2*x步。可得从b点开始绕环走x步,最后距离b点为y,那么从超出b点y步的位置开始走x步,则最后的点就是b点。
/**
 * 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) {
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;
        ListNode *slow = dummy, *fast = dummy;
        bool flag = false;
        while (fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if (fast == slow)
            {
                flag = true;
                break;
            }
        }
        if (!flag)
            return nullptr;
        ListNode *result = dummy;
        while (result != slow)
        {
            result = result->next;
            slow = slow->next;
        }
        return result;
    }
};