題目
請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
現有一個鏈表 – head = [4,5,1,9]
,它可以表示爲:
示例 1:
輸入: head = [4,5,1,9], node = 5
輸出: [4,1,9]
解釋: 給定你鏈表中值爲 5 的第二個節點,那麼在調用了你的函數之後,該鏈表應變爲 4 -> 1 -> 9.
示例 2:
輸入: head = [4,5,1,9], node = 1
輸出: [4,5,9]
解釋: 給定你鏈表中值爲 1 的第三個節點,那麼在調用了你的函數之後,該鏈表應變爲 4 -> 5 -> 9.
函數原型
C的函數原型:
void deleteNode(struct ListNode* node) {}
邊界判斷
void deleteNode(struct ListNode* node) {
if( node == NULL )
return;
if( node->next == NULL ){ // 要刪除的是最後一個結點(雖然題目說了非末尾結點)
free(node);
node = NULL;
return;
}
}
算法設計:鏈表刪除結點的特殊情況,改變值再刪除
這題和一般鏈表刪除結點情況不同。
通常鏈表刪除結點是通過待刪除結點
的前一個結點
,來檢測刪除哪一個結點,對於前一個結點它的 next
指針直接指向要刪除結點的下一個結點,把要刪除的這個結點跨過去即可。
如,刪除結點 3
。
通常會通過 3
前面的 2
來定位,而後會把指向 2
的 cur
指針指向 4
,跨過 3
。
這道題不太一樣,直接給定 3
這個結點,我們無法獲取 2
這個結點的信息。
咋辦?
我們可以動的就只有當前結點的指針。
把後面的值賦值
過來,再刪除掉後面的指針即可。
void deleteNode(struct ListNode* node) {
if( node == NULL )
return;
if( node->next == NULL ){ // 要刪除的是最後一個結點(雖然題目說了非末尾結點)
free(node);
node = NULL;
return;
}
node->val = node->next->val; // 用下一個值覆蓋
struct ListNode* del_node = node->next;
node->next = node->next->next;
free(del_node);
del_node = NULL; // free指針後,指針的值是一個隨機值,爲防止野指針,重新初始化
}
在面向對象的語言中,已知 node
但無法訪問 node
的上一個節點,因此不能修改上一個節點的 next
屬性。
於是得把 node
節點的值用下一個節點的值去覆蓋掉,然後把重複值的 node.next
給刪除掉也可以實現刪除結點。
但在 C
語言中,因爲是指針和結構體來表示鏈表,因此 node
和之前節點的 next
指向了內存中的同一地址,所以只要對這個地址做修改,上一個節點的 next
也同時被修改了。
*node = *(node->next);
完整代碼:
void deleteNode(struct ListNode* node) {
*node = *(node->next);
// *號把 [node->next] 裏面的 值(val)、指向下個結點(node->next->next) 都賦值給了 [node],但 [node] 的地址沒變。
}
- 時間複雜度:
- 空間複雜度: