對(duì)于一個(gè)鏈表,我們需要用一個(gè)特定閾值完成對(duì)它的分化,使得小于這個(gè)值的結(jié)點(diǎn)移到前面,等于的值在中間,大于該值的結(jié)點(diǎn)在后面,同時(shí)保證兩類結(jié)點(diǎn)內(nèi)部的位置關(guān)系不變。
本題最優(yōu)的解法是:
遍歷該鏈表,把其中小于/等于/大于的結(jié)點(diǎn)掛接在新的三個(gè)鏈表中,然后把這三個(gè)鏈表串接起來。因?yàn)闆]有new和delete操作,所以僅需很少的空間和時(shí)間開銷。
不完整代碼
ListNode* listDivide(ListNode* head, int val) {
//分別是三個(gè)鏈表的表頭和表尾指針。表尾方便在尾部掛接結(jié)點(diǎn)。
ListNode *h1=nullptr,*h2=nullptr,*h3=nullptr,*p1=nullptr,*p2=nullptr,*p3=nullptr;
ListNode *p=head;
while(p){
//遍歷,每個(gè)結(jié)點(diǎn)找到屬于它的三個(gè)鏈表中的一個(gè),掛接到尾部。
if(p->val<val){
//特別注意頭指針為空的情況。
if(h1==nullptr){
h1=p;
p1=h1;
}else{
p1->next=p;
p1=p1->next;
}
}else if(p->val==val){
if(h2==nullptr){
h2=p;
p2=h2;
}else{
p2->next=p;
p2=p2->next;
}
}else{
if(h3==nullptr){
h3=p;
p3=h3;
}else{
p3->next=p;
p3=p3->next;
}
}
p=p->next;
}
//拼合三個(gè)鏈表
p1->next=h2;
p2->next=h3;
p3->next=nullptr;//特別注意尾部的nullptr
return h1;
}
以上的代碼看似正常,其實(shí)是有問題的。問題在于拼合鏈表的時(shí)候,三個(gè)鏈表不一定每個(gè)都是有內(nèi)容的。空指針的拼接往往會(huì)出錯(cuò)。
結(jié)合上述冗長(zhǎng)的代碼,可以把三個(gè)鏈表指針放在數(shù)組內(nèi)進(jìn)行遍歷:利用一個(gè)belong函數(shù),得到每個(gè)結(jié)點(diǎn)應(yīng)該歸屬的鏈表,再進(jìn)行操作。拼合的時(shí)候,利用一個(gè)變量tail,只對(duì)不為空的鏈表進(jìn)行拼接。
int belong(const int a,const int b){
if(a<b)
return 0;
if(a==b)
return 1;
if(a>b)
return 2;
}
ListNode* listDivide(ListNode* head, int val) {
ListNode *h[3]={};
ListNode *t[3]={};
ListNode *p=head;
while(p){
int pos=belong(p->val,val);
if(h[pos]==nullptr){
h[pos]=p;
t[pos]=p;
}else{
t[pos]->next=p;
t[pos]=p;
}
p=p->next;
}
head=nullptr;
ListNode* tail=nullptr;
for(int i=0;i<3;++i){
if(h[i]){
if(!head){
head=h[i];
tail=t[i];
}else{
tail->next=h[i];
tail=t[i];
}
}
}
tail->next=nullptr;
return head;
}