提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、两两交换链表中的节点
这道题主要是需要使用到虚拟头节点和两个指向交换节点的指针
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if (head == nullptr || head->next == nullptr) return head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
//必须有两个节点
ListNode* cur = dummyHead;
//必须有头节点加指向两个要交换节点的指针
while (head != nullptr && head->next != nullptr) {
ListNode* tmp = head->next;
cur->next = tmp;
head->next = tmp->next;
tmp->next = head;
cur = head;
head = head->next;
}
return dummyHead->next;
}
};
二、删除链表的倒数第N个节点
1. 暴力解法,遍历算出链表的长度,减去n,得到待删除节点位置,再次遍历链表删除
2. 双指针(快慢指针),快慢指针之间相差n,当快指针指向末尾时,慢指针指向待删除结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
//1.暴力解法,遍历链表,查询链表长度,从而找到位置删除节点
//2.快慢指针,快指针比慢指针多走n步,当快指针下个节点为空,慢指针指向的下个节点就是要删除的节点
if (head == nullptr) return head;
ListNode* dummyHead = new ListNode();
dummyHead->next = head;
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
//快指针先走n步
while (n--) {
fast = fast->next;
}
//慢指针找到位置
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next;
slow = slow->next;
}
//删除
slow->next = slow->next->next;
return dummyHead->next;
}
};
三、面试题 02.07. 链表相交
分别遍历AB链表,算出链表长度,长减短,长的先走n步,再次遍历
/**
* 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) {
if (headA == NULL || headB == NULL) return NULL;
ListNode* curA = headA;
ListNode* curB = headB;
//1.计算两个链表的长度
int lenA = 0;
int lenB = 0;
while (headA != NULL) {
headA = headA->next;
lenA++;
}
while (headB != NULL) {
headB = headB->next;
lenB++;
}
headA = curA;
headB = curB;
if (lenA > lenB) {
int num = lenA - lenB;
while (num--) {
headA = headA->next;
}
}
if (lenB > lenA) {
int num = lenB - lenA;
while (num--) {
headB = headB->next;
}
}
//2.快慢指针
while (headA != NULL && headB != NULL) {
if (headA == headB) {
return headA;
}
headA = headA->next;
headB = headB->next;
}
return NULL;
}
};
四、环形链表II
1. 快慢指针,快指针走两步,慢指针走一步,两个如果相遇代表有环,否则没环
2. 从头结点到环形节点的长度等于快慢指针相遇节点到环形入口节点的长度
/**
* 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 == NULL || head->next == 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) {
ListNode* cur1 = head;
ListNode* cur2 = fast;
while (cur1 != cur2) {
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
}
return NULL;
}
};
总结
链表的主要问题和解决方法为增删差,虚拟头节点,双指针(快慢指针)
今天链表的题还算可以,能够独立写出,加油!继续努力!