目录
24. 两两交换链表中的节点
题目分析:
这一题,我认为它的难点就在于如何去调整链表之间的关系,以及要设置多个临时变量才存储,感觉是“双指针”的高级应用了。
但是即使是理解了代码的思路,在写代码的时候也会有新的问题,例如是要用while来遍历还是要以for或者if等进行判断等操作,以及一些next域的不断套用,会导致思路上的混乱,这个时候还是要多去捋几遍。还有一个就是循环条件是什么?循环结束时还需不需要进行其他的操作,例如销毁,释放空间,或者是考虑要返回的是什么节点?这些都需要多考虑一下,以免报错。
下面给的代码在力扣网上是测试通过的,但是漏了一个,没有给虚拟头节点进行空间的释放操作。
代码:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *linshi = new ListNode(0);
linshi->next = head;
ListNode *cur = linshi;
while(cur->next != NULL && cur->next->next != NULL) {
ListNode *t1 = cur->next;
ListNode *t2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = t1;
t1->next = t2;
cur = cur->next->next;
}
return linshi->next;
}
};
19.删除链表的倒数第N个节点
解题思路
这题又又又用到了双指针——快慢指针的使用,主要是注意题目已经提及是“倒数”,所以需要遍历到最后一个节点,然后依次往前推,那么如果使用了两个指针,就直接控制好两个指针之间的间隔,然后同时往后遍历,直到快指针所指向的节点为NULL时才停止移动,而这一题还有一点需要注意的就是我们删除节点的相关操作,一定要指向前一个节点,也就是我们在这一题中需要让间隔大1,或者是快指针先走一步,否则在删除节点的时候会出错,这一题的代码直接引用代码随想录上的参考代码,不再另行列出,主要还是理解思路。
参考代码(源于代码随想录官网)
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
while(n-- && fast != NULL) {
fast = fast->next;
}
fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummyHead->next;
}
};
面试题 02.07. 链表相交
题目分析
这一题其实我感觉在理解了题目的意思之后难度其实并不是很大,但也需要一定的理解。
注意一下题目的相关提示,在该题目的提示中,存在一条:“两个链表的最终节点始终相同,一旦他们相交,之后的所有节点将相等”,这也符合上了该题的参考代码了。
所以这一题的解题思路主要就是先判断一下两个链表的长度,然后将两个链表“右对齐”,也就是将尾端对齐,然后将两个指针分别放在对齐处的位置,同时向后遍历,因为抓住“一旦相交,之后的所有节点将相等”,所以就比较容易能得解了。
参考代码
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *ca = headA;
ListNode *cb = headB;
int la = 0;
int lb = 0;
while(ca != NULL) {
la++;
ca = ca->next;
}
while(cb != NULL) {
lb++;
cb = cb->next;
}
ca = headA;
cb = headB;
if(lb > la) {
swap(la,lb);
swap(ca,cb);//交换
}
int l = la - lb;
while(l){
ca = ca->next;
l--;
}
while(ca != NULL) {
if(ca == cb) {
return ca;
}
ca = ca->next;
cb = cb->next;
}
return NULL;
}
};
142.环形链表II
解题思路
这一题的思考过程还是有点难度的,感觉稍稍运用到了一点物理知识,经过一番理解过后还有点蒙圈,终究是需要多想几遍。
最详细的过程还是推荐大家到代码随想录上看老师的讲解,因为配有动画,理解起来肯定更为方便,文章链接:代码随想录 (programmercarl.com)https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
以下为我的个人理解:
首先要找到的是两个环的环的入口,可以假设一下有几种情况,①不存在环,也就是只有一条单链表;②不存在环,是一个单独的节点;③存在环,正好围成一个圈;④存在环,但不单单只是一个圈,会多出若干个节点为链,如下图所示。
而本题要进行解答,应该也是分成两个部分来进行判断,简单点说,就是如果判断过程中得知存在环,就直接返回了。
因此,这一题其实还是借用到了“双指针法”。而这一题的双指针,和上面的链表相交我认为有一点相似,也是快慢指针找相遇点,这一题也是先让一个快指针入环,接着慢指针入环,感觉有点物理上相对速度的那种味道,当两个指针在一个环内不断地走,以不同的速度,他们必定相遇。这一点理解起来并不难,我感觉对我来说难点是我该如何找到他们两的入口,因为两个指针入环的时间肯定是不一样的,他们可以转了n圈以后相遇,我应该如何去判断?而这一切都可以通过相关的数学证明,最好是画图,也就能理解了。
参考代码
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};