24 两两交换链表中的节点
题目链接:两两交换链表中的节点
思路
昨天遇到的题目是翻转链表,使用的是双指针法。今天的题目是两两交换链表中的节点,题目很清楚了,但是不太知道要怎么做,感觉自己都要自闭了。 参照解析,自己研究了一下,也算是看明白了。
这里先对为什么要需要虚拟头结点这个问题做一个粗浅的分析和回答:
- 链表最终返回的是头节点的指针,如果不使用虚拟头节点,就要单独对头结点进行处理,类似于203 移除链表元素那道题,所以使用虚拟头结点可以对头结点和不是头结点一个写法,这一点我已经做过验证。
然后对于这道题来说,就是直接模拟就可以了,也用不到什么算法。自己在纸上多画几次,就可以明白解析中说的步骤了。如果是在分不清指针的指向,可以用一个临时变量将所有的指针存起来,这样便于理解。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *cur;
ListNode *dummyHead = new ListNode(0);
dummyHead->next = head;
cur = dummyHead;
while(cur->next!=nullptr && cur->next->next!=nullptr)
{
ListNode *tmp = cur->next;
ListNode *tmp1 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp;
tmp->next = tmp1;
cur = cur->next->next;
}
return dummyHead->next;
}
};
19 删除链表中的倒数第N个节点
题目链接:删除链表中的倒数第N个节点
思路
现在我告诉你,这道题目应该使用双指针的算法,那么如何使用“双指针”呢?
假设链表有M
个元素,要删除倒数第N
个元素,则从开始到倒数第N
个元素还有M-N
个元素。我们让fast指针
先走N
个,刚好就剩下了slow指针
要走的M-N
个。这样我们不需要知道M
的大小。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *slow, *fast;
ListNode *dummyHead = new ListNode(0);
dummyHead->next = head;
fast = dummyHead;
slow = dummyHead;
while(n-- && fast->next!= nullptr)
{
fast = fast->next;
}
fast = fast->next;
while(fast != nullptr){
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummyHead->next;
}
};
02.07 链表相交
题目链接:02.07 链表相交
思路
这道链表相交的题目拿到手后,我们应该仔细研究下题目。若两个链表存在相交节点,**则相交节点后的所有节点都相等,**那我们从短链表的第一个元素开始遍历两个链表,就能找到相交节点(如果存在的话)。那么得先移动长链表的指针,和短链表对齐。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * curA = headA;
ListNode * curB = headB;
// 求链表的长度
int lenA = 0, lenB = 0;
while(curA != nullptr){
lenA++;
curA = curA->next;
}
while(curB != nullptr){
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if(lenB > lenA){
swap(lenA, lenB);
swap(curA, curB);
}
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
while(curA != nullptr){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};