題目:24.兩兩交換連結串列中的節點
思路:
設定虛擬頭結點,雙指標+臨時指標,(感覺也能遞迴,未嘗試)
時間複雜度:O(n)
空間複雜度:O(1)
坑:
1.又忘了 else{}和return
2.試圖訪問空指標,多個條件的順序問題及"&&""||"問題,cur->next要寫在cur->next->next前面
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if (head == nullptr)
return head;
else {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;
ListNode* post = head;
ListNode* pre = new ListNode(0);
ListNode* tmp;
while (cur->next!=nullptr&&cur->next->next!=nullptr) { //最佳化後,報錯,
/*1. 是“&&”不是“||”, 或的話,若cur->next為nullptr,則cur->next->next就訪問空指標了,
2.cur->next要寫在cur->next->next前面,理由同上
*/
pre = post->next;
tmp = pre->next;
cur->next = pre;
pre->next = post;
post->next=tmp; //提交heap-use-after-free報錯了,我的連結串列交換後,這裡斷了,
cur = post;
post = tmp;
}
return dummyhead->next;
}
}
};
/*未最佳化版本
while (post!=nullptr) { //可最佳化,迴圈結束條件不對,看迴圈體結束部分來思考
pre = post->next;
if(pre==nullptr){ //缺少判斷條件 長度為奇數的連結串列 這部分可最佳化
return dummyhead->next;
}
tmp = pre->next;
cur->next = pre;
pre->next = post;
post->next=tmp; //提交heap-use-after-free報錯了,我的連結串列交換後,這裡斷了,
cur = post;
post = tmp;
}
*/
補充:
1.heap-use-after-free on address
尾節點如果沒有rear->next=NULL;這個連結串列就會錯呢? 尾節點沒有明確指向,連結串列不完整,計算機認為連結串列未結束
2.懸掛指標(Dangling Pointer)。如果我們試圖訪問已經被釋放的記憶體,就會觸發"heap-use-after-free"錯誤。
題目:19.刪除連結串列的倒數第N個節點
思路:
1.遍歷連結串列獲取連結串列長度,然後刪除結點,釋放被刪除節點
2.進階要求是,使用一趟掃描實現-->隨想錄思路 啊 是快慢指標,快指標先走N+1步,
時間複雜度: O(n)
空間複雜度: O(1)
坑:
試圖訪問空指標,主要在cur->next時,cur可能為空指標
/** Definition for singly-linked list.同上*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead=new ListNode(0);
dummyHead->next=head;
ListNode* fast=dummyHead; //fast和slow初始指向虛擬head不是head
ListNode* slow=dummyHead;
ListNode* tmp;
n++; //刪除結點,slow要指向被刪除結點的前一個節點,所以fast要多走一步,slow和fast相差n+1步
while(n--&&fast!=nullptr){ //錯誤,需要判斷fast是否為空,
fast=fast->next;
}
while(fast!=nullptr){ //錯誤,試圖訪問空指標 fast不為空 不用->next
fast=fast->next;
slow=slow->next;
}
tmp=slow->next;
slow->next=slow->next->next;
delete tmp;
return dummyHead->next;
}
};
補充:
個人對快慢雙指標還是沒有理解到位
雙指標解題:
1.指標相鄰:刪除某個結點,或交換兩個結點
2.指標不相鄰,快滿指標間隔N步
題目:面試題02.07.連結串列相交
思路:
1.兩個這指標分別指向a,b,兩層迴圈遍歷,比較->next是否相等,有點繁瑣
2.看了leetcode的引導式提示:從兩連結串列長度相同時相交到不同長度,一個先走差值步,使得二者相同才判斷;
時間複雜度:O(n + m)
空間複雜度:O(1)
坑:
- 當兩連結串列長度相同時,兩連結串列不相交可以和相交放一起判斷
- 使用pa->next判空,則少算了最後一個pa節點
- 沒比較兩連結串列長度,就預設進行下去了;
/** Definition for singly-linked list.同上*/
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
ListNode* pA = headA;
ListNode* pB = headB;
int m = 0, n = 0, diff = 0; // diff表示兩連結串列的差值 (用英語gap也行)
pA = headA; // 指標返回頭結點
pB = headB;
while (pA != nullptr) { // 錯誤,pa->next判空,則少算了最後一個pa節點
pA = pA->next;
m++;
}
while (pB != nullptr) {
pB = pB->next;
n++;
}
pA = headA;
pB = headB;
// 錯誤,m和n的大小沒有判斷,
if (m < n) { // 交換使得,pA和m表示較長的連結串列
swap(pA, pB);
swap(m, n);
}
diff = m - n;
while (diff--) {
pA = pA->next;
}
while (pA!=nullptr) {
if(pA==pB)
return pA;
pA = pA->next;
pB = pB->next;
}
return NULL;
}
};
題目:142.環形連結串列Ⅱ
思路:
坑:
補充:
今日總結
連結串列類的題主要還是看思路,想得到關鍵,就後面很順利