文档讲解:代码随想录 (programmercarl.com)
视频讲解:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili
状态:没写出来
想到了用三个指针来实现,但是出错点在于,我把三个指针都写到了while循环的外面,感觉这还好,但是提交之后发现超时了,后来对比了一下代码随想录的代码,发现有两个地方不一样。
第一个就是把三个指针都写到了while循环的外面,导致两两交换节点之后,我还要再对定义的指针进行移动的操作,这无疑是增加了工作量;
第二个就是while中的判断条件,我写的是tmp!=nullptr,还是同样的道理,移动后还要取值判断,这也增加了代码的工作量。
虚拟头结点确实好用。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode();
dummyhead->next = head;
ListNode* cur = dummyhead;
while(cur->next != nullptr && cur->next->next != nullptr){
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;
cur->next = tmp->next;
tmp->next = tmp1;
cur->next->next = tmp;
cur = cur->next->next;
}
return dummyhead->next;
}
};
文档讲解:代码随想录 (programmercarl.com)
视频讲解:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点_哔哩哔哩_bilibili
状态:勉强写出
这道题目卡的时间最久,我一开始的思路是,先求出链表总长度,再用总长度减去n,就可以把问题巧妙地转变为删除链表的第n个节点。
但是leetcode总是报错runtime error: member access within null pointer of type ‘ListNode‘,上网搜了搜,原因是cur->next = cur->next->next;这句话如果cur->next为空,那么就会有给空指针赋值的风险,所以要加上一句判断 if(cur->next!=nullptr),最终才顺利通过。
但是不是所有情况都可以用加上一个条件判定的方法来解决呢?
其实不是,有一篇文章已经有例子和详细清晰的解释,在此不赘述了。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode();
dummyhead->next = head;
ListNode* cur = dummyhead;
int length = Length(dummyhead);
for(int i = 1;i<length-n+1;i++){
cur = cur->next;
}
if(cur->next!=nullptr)
cur->next = cur->next->next;
return dummyhead->next;
}
int Length(ListNode* dummyhead){
int count = 0;
ListNode* cur = dummyhead->next;
while(cur != nullptr){
++count;
cur = cur->next;
}
return count;
}
};
这是仿照代码随想录的方法写的算法,大概思想就是,快指针和慢指针形成一个n+1的区间,当快指针指向空时,慢指针的下一个节点正好就是倒数第n个节点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode();
dummyhead->next = head;
ListNode* slow = dummyhead;
ListNode* fast = dummyhead;
while(fast != nullptr && n!=0){
--n;
fast = fast->next;
}
fast = fast->next;
while(fast != nullptr){
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummyhead->next;
}
};
文档讲解:代码随想录 (programmercarl.com)
视频讲解:没有
状态:用暴力的方法写出来的
这道题用暴力的方法是可以做出来的,指针A每移动一次,就让指针B从头到尾扫描B链表,看看有没有地址重合。 但是时间复杂度太高了。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* dummyheadA = new ListNode();
ListNode* dummyheadB = new ListNode();
dummyheadA->next = headA;
dummyheadB->next = headB;
ListNode* curA = dummyheadA;
ListNode* curB = dummyheadB;
while(curA->next != nullptr){
curB = dummyheadB;
while(curB->next != nullptr){
if(curB->next == curA->next){
ListNode* p = curA->next;
return p;
}
curB = curB->next;
}
curA = curA->next;
}
return nullptr;
}
};
这个是代码随想录上提供的算法,我仿写了一遍,大概思想就是AB链尾对齐遍历。
时间复杂度是O(n) ,空间复杂度是O(1)。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
while(curA != nullptr){
++lenA;
curA = curA->next;
}
while(curB != nullptr){
++lenB;
curB = curB->next;
}
curA = headA;
curB = headB;
if(lenB > lenA){
swap(lenA,lenB);
swap(curA,curB);
}
int gap = lenA-lenB;
while(curA != nullptr && gap > 0){
--gap;
curA = curA->next;
}
while(curA != nullptr && curB != nullptr){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return nullptr;
}
};
文档讲解:代码随想录 (programmercarl.com)
视频讲解:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili
状态:没写出来
快慢指针的思想,就跟在操场跑步类似,比你跑得快的人超过你一次迟早超过你第二次。
这道题难就难在运用到了数学的思想,要好好理解。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != nullptr && fast->next != nullptr){
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 nullptr;
}
};