￼Remove Duplicates from Sorted List II

Question

Given a sorted linked list, delete all nodes that have duplicate numbers,
leaving only distinct numbers from the original list.

Example
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.


題解

ListNode *dummy = new ListNode(0);
ListNode *node = dummy;


1. 此題需要將值相等的節點全部刪掉，而刪除鏈表的操作與節點前後兩個節點都有關系，故需要涉及三個鏈表節點。且刪除單向鏈表節點時不能刪除當前節點，只能改變當前節點的next指向的節點。
2. 在判斷val是否相等時需先確定node->nextnode->next->next均不為空，否則不可對其進行取值。

C++ - Wrong

/**
* Definition of ListNode
* class ListNode {
* public:
*     int val;
*     ListNode *next;
*     ListNode(int val) {
*         this->val = val;
*         this->next = NULL;
*     }
* }
*/
class Solution{
public:
/**
*/
return NULL;
}

ListNode *dummy;
ListNode *node = dummy;

while (node->next != NULL && node->next->next != NULL) {
if (node->next->val == node->next->next->val) {
int val = node->next->val;
while (node->next != NULL && val == node->next->val) {
ListNode *temp = node->next;
node->next = node->next->next;
delete temp;
}
} else {
node->next = node->next->next;
}
}

return dummy->next;
}
};


錯因分析

1. 節點dummy的初始化有問題，對class的初始化應該使用new
2. 在else語句中node->next = node->next->next;改寫了dummy-next中的內容，返回的dummy-next不再是隊首元素，而是隊尾元素。原因很微妙，應該使用node = node->next;，node代表節點指標變數，而node->next代表當前節點所指向的下一節點地址。具體分析可自行在紙上畫圖分析，可對指標和鏈表的理解又加深不少。

Python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
# @return {ListNode}
return None

dummy = ListNode(0)
node = dummy
while node.next is not None and node.next.next is not None:
if node.next.val == node.next.next.val:
val_prev = node.next.val
while node.next is not None and node.next.val == val_prev:
node.next = node.next.next
else:
node = node.next

return dummy.next


C++

/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
if (head == NULL) return NULL;

ListNode *dummy = new ListNode(0);
ListNode *node = dummy;
while (node->next != NULL && node->next->next != NULL) {
if (node->next->val == node->next->next->val) {
int val_prev = node->next->val;
// remove ListNode node->next
while (node->next != NULL && val_prev == node->next->val) {
ListNode *temp = node->next;
node->next = node->next->next;
delete temp;
}
} else {
node = node->next;
}
}

return dummy->next;
}
};


Java

/**
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int x) { val = x; }
* }
*/
public class Solution {
if (head == null) return null;

ListNode dummy = new ListNode(0);
ListNode node = dummy;
while(node.next != null && node.next.next != null) {
if (node.next.val == node.next.next.val) {
int val_prev = node.next.val;
while (node.next != null && node.next.val == val_prev) {
node.next = node.next.next;
}
} else {
node = node.next;
}
}

return dummy.next;
}
}


源碼分析

1. 首先考慮異常情況，head 為 NULL 時返回 NULL
2. new一個dummy變數，dummy->next指向原鏈表頭。
3. 使用新變數node並設置其為dummy頭節點，遍歷用。
4. 當前節點和下一節點val相同時先保存當前值，便於while循環終止條件判斷和刪除節點。注意這一段代碼也比較精煉。
5. 最後返回dummy->next，即題目所要求的頭節點。

Python 中也可不使用is not None判斷，但是效率會低一點。