今日任务
- 24. 两两交换链表中的节点
- 19.删除链表的倒数第N个节点
- 面试题 02.07. 链表相交
- 142.环形链表II
- 总结
感觉训练营在逐渐加大训练量,也提前看了一下后续的一些题目,感觉数量不少,昨天一天的事请假了,3.19来补卡。
一、 两两交换链表中的节点
题目解读:就是和标题一样吧,为了防止投机取巧,还特意点明只能进行节点交换,不能修改内部值,这也就是算法特训的一些本质吧,有些题看着用一些别的方法很简单,但却失去了训练的意义,所以不能投机取巧。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* duhead = new ListNode(0);
duhead->next = head;
ListNode* cur = duhead;
while(cur->next!= NULL&&cur->next->next!= NULL){
ListNode* temp = cur->next->next->next;
ListNode* d1 = cur->next;
cur->next = cur->next->next;
cur->next->next = d1;
cur->next->next->next = temp;
cur = cur->next->next;
}
return duhead->next;
}
};
一开始想自己尝试一下,发现逻辑乱套了。看了步骤图重新写了一个,感觉逻辑比较清晰,而且和题解基本是一样的。深刻认识到了对于链表,逻辑真的很重要。
二、删除链表的倒数第n个节点
题目解读:由于这个题需要删除的结点是倒数第n个,就可以使用双指针形成一个窗口,使得快指针指向最后一个元素时,慢指针指向倒数第n+1个节点(方便指向倒数第n个节点)。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
while(n--&&fast !=NULL){
fast = fast->next;
}
fast = fast->next;
while(fast !=NULL){
fast = fast->next;
slow = slow->next;
}
ListNode* temp = slow->next;
slow->next = slow->next->next;
delete(temp);
return dummy->next;
}
};
做了一遍,感觉整体思路没有问题,在初始结点的选择和约束条件的逻辑思考还有所欠缺。
附上题解代码随想录 (programmercarl.com)
三、 链表相交(面试题)
题目解读:一开始读这个题的时候我以为需要后面都一样,但后来感觉并不需要,只要一个节点相交就好了。
整体思路是选择一个较长的链表,然后让长链表走到剩余短链表元素时的长度。然后后续再找相交结点。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
根据思路写完了代码,对照感觉没啥问题,检查了几遍后决定不纠结,直接附上题解代码和题解。
四、环形链表
题目解读:这个题如果单单个人思考的话我个人觉得还是有难度的。之前看过一遍,其实知道了思路之后其实还是不是那么难的。主要还是靠快慢指针。
/**
* 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) {
ListNode* fast =head;
ListNode* slow =head;
while(fast!=NULL&&fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast ==slow){
ListNode* index1 = fast;
ListNode* index2 = head;
while(index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
在整体思路有并且知道结论的时候,这个题还是比较容易的。
附上题解:代码随想录 (programmercarl.com)
最后总结:1、虚拟头节点可以解决头节点需要单独处理的情况。
2、基础很重要,链表的基本操作看着简单,但是写起来还是有一定难度。
3、反转链表我个人迭代法和递归法的思路其实是一样的,但如果使用栈的话其实也是挺方便的。
4、删除节点需要结合虚拟头节点和双指针法。
5、链表相交和环形链表都会用到双指针法
6、写链表题逻辑真的很重要。
感觉写了不到俩小时,感觉链表还是思路和逻辑最重要。