目录
24. 两两交换链表中的节点 - 實作
思路
Code
19.删除链表的倒数第N个节点
思路
Code
160. 链表相交
思路
Code
142.环形链表II
思路
Code
總結
自己实现过程中遇到哪些困难
今日收获,记录一下自己的学习时长
第二章 鏈表的學習總結
鏈表的定義
鏈表的操作
刪除節點
插入節點
參考資料
24. 两两交换链表中的节点
19.删除链表的倒数第N个节点
160. 链表相交
142.环形链表II
兩兩鏈表交換有兩種狀況,分別是鏈表長度為奇數或偶數
根據這個狀況,條件設定要是能夠符合這兩種狀況
cur 一定要在交換的兩節點前面
但如果直接座椅上交換步驟會出現一件事情
所以我們要先將cur→next (A)以及 cur→next→next→next(C)的位置先保存,至於cur→next→next(B)則會因為步驟1 直接成為cur→next
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;
while(cur->next != NULL && cur->next->next != NULL){
ListNode* tmp1 = cur->next;
ListNode* tmp2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp1;
tmp1->next = tmp2;
cur = tmp1;
}
return dummyhead->next;
}
};
使用雙指針的思路,fast先走n+1次後,在開始讓slow走,直到fast走到NULL後,slow的下一個節點就是要刪除的節點。
為甚麼是n+1次,因為如果fast先走n次,slow會在fast指向NULL時,剛好走到要刪除的節點,但需要刪除的節點必須要在這個節點之前,所以如果fast只走n步,是不夠的,要走n+1次,讓slow剛好走到倒數第n個節點之前
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode();
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
dummyHead->next = head;
n++; // 因為迴圈會n-- 所以需要先把要n+1的值補上
while(n-- && fast != NULL){
fast = fast->next;
}
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
ListNode* tmp = slow->next;
slow->next = slow->next->next;
return dummyHead->next;
}
};
這題一開始想不明白,看卡哥的講解也有點矇,感謝算法訓練營的小夥伴,讓我理解好了
這題有兩個重點
搞清楚這兩個重點,後面就比較簡單了
錯誤代碼
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int lenA = 0;
int lenB = 0;
ListNode* curA = headA;
ListNode* curB = headB;
while(curA != NULL){
curA = curA->next;
lenA++;
}
while(curB != NULL){
curB = curB->next;
lenB++;
}
curA = headA;
curB = headB;
if(lenB > lenA){
swap(curA, curB);
swap(lenA, lenB);
}
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
while(curA != NULL){
curA = curA->next; // 應該先比較後移動,因為先移動了,所以出錯
curB = curB->next;
if(curA == curB){
return curA;
}
}
return NULL;
}
};
正確代碼
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int lenA = 0;
int lenB = 0;
ListNode* curA = headA;
ListNode* curB = headB;
while(curA != NULL){
curA = curA->next;
lenA++;
}
while(curB != NULL){
curB = curB->next;
lenB++;
}
curA = headA;
curB = headB;
if(lenB > lenA){
swap(curA, curB);
swap(lenA, lenB);
}
int gap = lenA - lenB;
while(gap--){
curA = curA->next;
}
while(curA != NULL){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
有三個重要思路
錯誤代碼
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* dummyHead = new ListNode();
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
dummyHead->next = head;
while(fast != NULL ){ //少判斷fast->next != NULL , 如果沒有判斷,可能就會導致fast->next->next是空指針操作
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
ListNode* index1 = slow;
ListNode* index2 = dummyHead;
while(index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
正確代碼
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* dummyHead = new ListNode();
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
dummyHead->next = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
ListNode* index1 = slow;
ListNode* index2 = dummyHead;
while(index1 != index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
今天主要是在160.鏈表相交理解題目上出現了問題,我很慶幸我加入了算法訓練營,讓我在有問題的時候可以有人詢問
另外就是對於指標的邊界判斷以及順序,要避免務操作,這方面還需要再多做加強,現在還是很常在寫程式時沒有考慮到這些條件,而報錯
今天大概學了3hr 主要是看卡哥的影片後,自己拿白紙重新捋一次想法,在寫代碼上其實就會輕鬆很多,思緒非常清晰,如果報錯,也可以重新對照想法與卡哥的解釋,看一下是不是自己沒考慮清楚
整理了四個重點如下:
再來這裡必須要在回顧第三天的鏈表理論基礎中的鏈表定義以及操作
鏈表可以想像是一串粽子,粽子(資料),綁粽子的繩子(指標),這兩個形成一個節點,假設有連接兩個粽子之間的繩子則可以當作節點的連結。
鏈表程式定義
struct ListNode{
int val; //數據,這個粽子的內餡是甚麼
ListNode *next; //指標,指向下一個值,是否讓我可以連結下一個粽子的重要關鍵
ListNode(int x): val(x), next(NULL){} //節點的構造函數,就有點像是一開始要不要定義這個粽子是甚麼餡料
}
可不可以有多個數據,就是粽子的內餡可不可以多一點,可以!
但內餡一多,粽子就會變重,道理一樣,如果數據一多,節點就會佔更多空間
struct ListNode{
int val; //數據,這個粽子的內餡是甚麼
char val2;
long val3;
ListNode *next; //指標,指向下一個值,是否讓我可以連結下一個粽子的重要關鍵
ListNode(int x,char y, long z): val(x), val2(y), val3(z), next(NULL){} //節點的構造函數,就有點像是一開始要不要定義這個粽子是甚麼餡料
};
那可不可以不要有構造函數,可以,但在後續操作時,就不能直接賦值給節點了
//有構造函數的:
ListNode* head = new ListNode(1,'2',3);
//無構造函數的
ListNode* head = new ListNode();
head->val = 1;
head->val2 = '2';
head->val3 = 3;
鏈表一刷的學習總結如上。
题目链接/文章讲解/视频讲解: https://programmercarl.com/0024.两两交换链表中的节点.html
题目链接/文章讲解/视频讲解:https://programmercarl.com/0019.删除链表的倒数第N个节点.html
题目链接/文章讲解:https://programmercarl.com/面试题02.07.链表相交.html
题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.环形链表II.html