LeetCode 24 两两交换链表中的节点
题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)
设置虚拟头结点。设置了两个遍历节点pre、cur,未用临时节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummynode = new ListNode(0, head);
ListNode* pre = dummynode;
ListNode* cur = head;
while (cur && cur->next) {//交换的是cur和cur->next
pre->next = cur->next;
cur->next = cur->next->next;
pre->next->next = cur;
pre = cur;
cur = cur->next;
}
return dummynode->next;
}
};
LeetCode 19删除链表的倒数第N个结点
题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
一开始的想法就是将链表遍历两遍:
第一遍遍历确定链表总结点数count,删除倒数第n个结点=正数第(count - n + 1)个结点
第二次遍历就是删除第(m - n + 1)个结点即可
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummynode = new ListNode(0, head);
ListNode* cur = head;
int count = 0;
while (cur) {
count++;
cur = cur->next;
}
//删除第count-n+1个结点
int index = count - n + 1;
if (index <= 0) return head;
cur = dummynode;
while (--index) {//找到被删除结点的前一个结点
cur = cur->next;
}
ListNode* tmp = cur->next;
cur->next = tmp->next;
delete tmp;
return dummynode->next;
}
};
双指针法
设置两个指针——slow和fast,并且让两个指针之间相隔n个结点
同时移动slow和fast,目的是为了fast指向链表结尾的nullptr时,slow刚好指向需被删除结点的前一个位置
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummynode = new ListNode(0, head);
ListNode* slow = dummynode;
ListNode* fast = head;
//目的是让slow和fast之间相隔n个结点
while (fast && n--) {
fast = fast->next;
}
//fast指向链表结尾的nullptr时,slow指向需被删除结点的前一个位置
while (fast) {
slow = slow->next;
fast = fast->next;
}
//删除
ListNode* tmp = slow->next;
slow->next = tmp->next;
delete tmp;
return dummynode->next;
}
};
LeetCode 面试题02.07链表相交
题目链接:面试题 02.07. 链表相交 - 力扣(LeetCode)
可能因为是二刷,凭本能而写出了??!!!
让两个链表右对齐:求出节点个数差值;让长链表的指针移动到遍历相交的起始位置
遍历两个链表
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
int countA = 0, countB = 0;
ListNode* curA = headA;
ListNode* curB = headB;
while (curA) {
countA++;
curA = curA->next;
}
while (curB) {
countB++;
curB = curB->next;
}
if (countA < countB) {
swap(headA, headB);
swap(countA, countB);
}
curA = headA;
int index = countA - countB;
while (index) {
curA = curA->next;
}
curB = headB;
while (curA && curB) {
if (curA == curB) return curA;
curA = curA->next;
curB = curB->next;
}
return nullptr;
}
};
LeetCode 142环形链表II
题目链接:142. 环形链表 II - 力扣(LeetCode)
直接用哈希表存储已经遍历过的结点,如果当前遍历节点已经存储在哈希表中则有环
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
unordered_set<ListNode*> node;//用哈希表存储已经遍历过结点
ListNode* cur = head;
while (cur && node.find(cur) != node.end()) {
node.insert(cur);
cur = cur->next;
}
return cur == nullptr ? nullptr : cur;//cur为nullptr则说遍历到链表结尾,无环;否则返回环的起始位置
}
};
双指针法/快慢指针法
若存在环,快慢指针相遇一定在环内
相遇时二者所走路径:2* slow = fast,
即为
化简为
,
这个多遍到底是几遍无所谓,总之就是当slow、fast相遇之后,fast继续走【环外节点数】这些步,一定到达环的起点。
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
//slow每次走一步,fast每次走两步
slow = slow->next;
fast = fast->next->next;
//当slow和fast相遇后,再走环外结点个数就走到换的起始位置了
if (slow == fast) {
slow = head;//slow走环外的节点
while (slow != fast) {
slow = slow->next;
fast = fast->next;//fast在环内继续走
}
return slow;//slow、fast相遇的时候就是环的起点
}
}
return nullptr;
}
};
链表篇总结
要掌握虚拟头结点的设置、双指针法、(按索引)对链表内节点的增加删除
注意增加和删除时断链的前后顺序