很老的一道面試題,經典解法是用哈希表求解。如果不允許申請額外的存儲空間,我能想到的就是用歸並排序來搞,在歸並的比較過程中刪除重復元素,但成立的前提是允許改變原始鏈表元素的順序。
用鏈表做歸並排序有個方便的地方,就是不用像處理普通數組那樣額外申請空間, 正好滿足問題的附加條件。不方便的地方在於把規模n的問題分解為n/2子問題的時候,沒法直接求得中點。簡單粗暴的做法是分解問題時先遍歷到中點,這樣會增加n/2*logn的復雜度,湊合。
struct Node{
double v;
Node* next;
}; // 鏈表元素
// 合並2個有序的鏈表,順帶刪除重復元素
static Node* mergeList(Node* pHead1,Node* pHead2)
{
Node* pHead = NULL;
Node* pTail =NULL;
while(pHead1 != NULL && pHead2 != NULL)
{
Node* pMin; // 需要一個臨時變量保存當前的最小值
if(pHead1->v < pHead2->v)
{
pMin = pHead1;
pHead1 = pHead1->next;
}
else if(pHead1->v > pHead2->v)
{
pMin = pHead2;
pHead2 = pHead2->next;
}
else{ // 刪除重復元素
Node* t = pHead2;
pHead2 = pHead2->next;
delete t;
continue; // 注意
}
if(pHead == NULL){
pHead = pMin;
pTail = pMin;
}
else{
pTail->next = pMin; // 注意要更新->next
pTail = pMin; // 更新合並后的鏈表尾
}
}
if(pHead==NULL){
pHead = (pHead1==NULL) ? pHead2 : pHead1;
}
else{
pTail->next = (pHead1==NULL) ? pHead2 : pHead1; // 注意是->next
}
return pHead;
}
// 第二個入參為鏈表的長度
static Node* mergeSort(Node* pHead, int size)
{
if(size == 1){ return pHead;}
int half = size/ 2;
Node* last = pHead; // 遍歷到左邊list的最后一個元素
for( int i = 0; i < half- 1;++i)
{
last = last->next;
}
Node* right = last->next;
last->next = NULL; // 分割鏈表前記得保存為right
mergeSort(pHead,half);
mergeSort(right,size-half);
return mergeList(pHead,right);
}
// 最外層的主函數
Node* deleteDups(Node* pHead)
{
if(pHead == NULL){ return NULL;}
int size= 0;
Node* t = pHead;
while(t != NULL)
{
++size;
t = t->next;
}
return mergeSort(pHead,size);
}
double v;
Node* next;
}; // 鏈表元素
// 合並2個有序的鏈表,順帶刪除重復元素
static Node* mergeList(Node* pHead1,Node* pHead2)
{
Node* pHead = NULL;
Node* pTail =NULL;
while(pHead1 != NULL && pHead2 != NULL)
{
Node* pMin; // 需要一個臨時變量保存當前的最小值
if(pHead1->v < pHead2->v)
{
pMin = pHead1;
pHead1 = pHead1->next;
}
else if(pHead1->v > pHead2->v)
{
pMin = pHead2;
pHead2 = pHead2->next;
}
else{ // 刪除重復元素
Node* t = pHead2;
pHead2 = pHead2->next;
delete t;
continue; // 注意
}
if(pHead == NULL){
pHead = pMin;
pTail = pMin;
}
else{
pTail->next = pMin; // 注意要更新->next
pTail = pMin; // 更新合並后的鏈表尾
}
}
if(pHead==NULL){
pHead = (pHead1==NULL) ? pHead2 : pHead1;
}
else{
pTail->next = (pHead1==NULL) ? pHead2 : pHead1; // 注意是->next
}
return pHead;
}
// 第二個入參為鏈表的長度
static Node* mergeSort(Node* pHead, int size)
{
if(size == 1){ return pHead;}
int half = size/ 2;
Node* last = pHead; // 遍歷到左邊list的最后一個元素
for( int i = 0; i < half- 1;++i)
{
last = last->next;
}
Node* right = last->next;
last->next = NULL; // 分割鏈表前記得保存為right
mergeSort(pHead,half);
mergeSort(right,size-half);
return mergeList(pHead,right);
}
// 最外層的主函數
Node* deleteDups(Node* pHead)
{
if(pHead == NULL){ return NULL;}
int size= 0;
Node* t = pHead;
while(t != NULL)
{
++size;
t = t->next;
}
return mergeSort(pHead,size);
}