LeetBook链表专题题解

链表

单链表

在这里插入图片描述

设计单链表

注意:中间删除结点和中间插入结点都不难,但是任意插入或删除结点的时候需要考虑到头插或头删。要注意的是如果头结点改变了,那head结点就要改变,所以当插入结点或者删除结点的时候需要特别小心头结点的插入删除。

class MyLinkedList {
   
private:
	struct ListNode
	{
   
		int val;
		ListNode* next;
		ListNode(int v = 0) :val(v), next(nullptr) {
   }
	};
	int size;// 链表的长度
	ListNode* head;// 头指针
public:
	/** Initialize your data structure here. */
	MyLinkedList() :size(0), head(nullptr) {
   
	}

	/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
	int get(int index) {
   
		if (index + 1 > size)
			return -1;
		ListNode* cur = head;
		while (index--)
		{
   
			cur = cur->next;
		}
		return cur->val;
	}

	/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
	void addAtHead(int val) {
   
		addAtIndex(0, val);
	}

	/** Append a node of value val to the last element of the linked list. */
	void addAtTail(int val) {
   
		addAtIndex(size, val);
	}

	/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
	void addAtIndex(int index, int val) {
   
		ListNode* newNode = new ListNode(val);
		// 头插
		if (index <= 0)
		{
   
			newNode->next = head;// newNode指向head,然后newNode变成head
			head = newNode;
			size++;
			return;
		}
		// 索引大于链表的长度
		if (index > size)
			return;
		// 中间插入结点
		ListNode* prev = head;
		while (--index)// 找到index前一个结点
		{
   
			prev = prev->next;
		}
		newNode->next = prev->next;
		prev->next = newNode;
		size++;// 链表长度+1
	}

	/** Delete the index-th node in the linked list, if the index is valid. */
	void deleteAtIndex(int index) {
   
		if (index < 0 || index >= size)// 没有索引会<0或者>=size
			return;
        if (index == 0)// 删除头结点
        {
   
            ListNode* delNode = head;
            head = head->next;
            delete delNode;
        }
        else// 删除中间结点
        {
   
            ListNode* prev = head;
            while (-- index)// 找到index前一个结点
            {
   
                prev = prev->next;
            }
            ListNode* delNode = prev->next;
            prev->next = delNode->next;
            delete delNode;
        }
        size --;// 链表长度-1
	}
};

链表中的双指针

环形链表

(快慢指针)

注意一点,因为fast和slow指针初始化的时候都需要初始化为head,所以就可以用fast!=slow来作为while循环的条件

class Solution {
   
public:
    bool hasCycle(ListNode *head) {
   
        if (head == nullptr || head->next == nullptr) return false;
        ListNode* fast = head, *slow = head;
        // 方法1
        while (fast && fast->next)
        {
   
            fast = fast->next->next;// fast每次走两步
            slow = slow->next;// 慢指针每次走一步
            if (fast == slow)
                return true;
        }
        return false;
        // 方法2
        // while (fast != nullptr)
        // {
   
        //     fast = fast->next;
        //     if (fast != nullptr)
        //         fast = fast->next;
        //     slow = slow->next;
        //     if (fast == slow)
        //         return true;
        // }
        // return false;
    }
};

环形链表Ⅱ

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PM45s1zx-1623394221098)(C:\Users\张昊宇\AppData\Roaming\Typora\typora-user-images\image-20210608100225917.png)]

(快慢指针)
class Solution {
   
public:
    ListNode *detectCycle(ListNode *head) {
   
        // 判断是否有环
        ListNode* fast = head, *slow = head;
        ListNode* meetNode = nullptr;
        while (fast && fast->next)
        {
      
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow)
            {
   
                meetNode = fast;
                break;
            }
        }
        // 如果链表中没有环就返回nullptr
        if (meetNode == nullptr)
            return nullptr;
        // 让head和meetNode同时走知道相遇,相遇的位置就是入环口
        while (head != meetNode)
        {
   
            head = head->next;
            meetNode = meetNode->next;
        }
        return meetNode;
    }
};

相交链表

(指针交错遍历1)

因为相交点之后的结点数是相同的,但是相交点之前的结点数不同,如果让两个指针走的结点数相同的话就可以同时到达相交点。所以让curA指针走完curA链表之后再去走curB链表,让curB指针走完curB链表之后,去走curA链表,这样就可以弥补相交点之前结点数可能不同,而导致走的结点数不同。

概括:走到尽头见不到你,于是走过你来时的路,等到相遇时才发现,你也走过我来时的路

class Solution {
   
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
   
        ListNode* curA = headA, *curB = headB;
        while (curA != curB)
        {
   
            curA = curA->next;
            curB = curB->next;
            // 如果同时走到nullptr就说明链表没有相交点
            if (curA == nullptr && curB == nullptr) return nullptr;
            // 如果链表走完一条链表就再去走另一条链表
            if (curA == nullptr) curA = headB;
            if (curB == nullptr) curB = headA;
        }
        return curA;
    }
};
(指针交错遍历2)
class Solution {
   
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
   
        ListNode* curA = headA, *curB = headB;
        while (curA != curB)
        {
   
            curA = curA ? curA->next : headB;
            curB = curB ? curB->next : headA;
        }
        return curA;
    }
};
(链表相联找入环口)
class Solution {
   
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
   
        // 找到链表A的尾巴
        ListNode* cur = headA;
        while (cur->next != nullptr)
            cur = cur->next;
        // 将链表A连接到链表B上
        cur->next = headB;
        // 找入环口
        ListNode* fast = headA, *slow = headA;
        while (fast && fast->next)
        {
   
            fast = fast->next->next;
            slow = slow->next;
            if (slow == fast)
            {
   
                ListNode* prev = headA;
                while (prev != slow)
                {
   
                    prev = prev->next;
                    slow = slow->next;
                }
                // 恢复链表
                cur->next = nullptr;
                return prev;
            }
        }
        // 恢复链表
        cur->next = nullptr;
        return nullptr;
    }
};
(补齐链表差数)
/**
 * 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) {
   
        int cntA = 0, cntB = 0;
        ListNode* curA = headA, *curB = headB;
        // 统计链表的长度
        while (curA)
        {
   
            curA = curA->next;
            cntA ++;
        }
        while (curB)
        {
   
            curB = curB->next;
            cntB ++;
        }
        // greater是长的链表,less是短的链表
        ListNode* greater = cntA > cntB ? headA : headB;
        ListNode* less = greater == headA ? headB : headA;
        // 让长链表先走差数步,补齐差数
        int n = abs(cntA - cntB);
        for (int i = 0; i < n; i ++)
            greater = greater->next;
        // 长链表和短链表同时走,直到相遇
        while (greater != less)
        {
   
            greater = greater->next;
            less = less->next;
        }
        return greater;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值