如果兩個單鏈表相交,那應該呈「y」字形,也就是從交點以後的部分是兩個鍊錶的公共節點。
所以,判斷是否相交只要看兩個鍊錶的最後乙個節點是否為同乙個即可。
那麼如何找到交點呢?設兩個單鏈表的長度分別為l1、l2,(假設l1>l2),則(l1-l2)的值就是交匯之前兩個鍊錶的長度差;
因此,只有讓更長的鍊錶先走l1-l2步,然後兩個鍊錶開始一起走,如果某次走到乙個相同的節點,該節點即為交點。
c**實現:
typedef struct該問題還有一種思路,就是將其中乙個鍊錶首尾相連,然後檢測另外乙個鍊錶是否有環,如果存在環,則兩個鍊錶相交。_listnode listnode;
static
int getlistlength(listnode *t)
returnn;}
static listnode* findfirstcommonnode(listnode *t1, listnode *t2)
for (i=0; i)
while (t1 && t1 !=t2)
return
t1;
}
如果乙個單鏈表有環,那應該呈「6」字形。
設定兩個指標(fast, slow),初始值都指向頭節點,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入環,而slow後進入環,兩個指標必定 相遇:如果鍊錶是呈"o"字形,則slow剛好遍歷完一次的時候,與fast相遇;如果呈「6」字形,則更早相遇。
當fast若與slow相遇時,slow還沒有遍歷完鍊錶,而fast已經在環內迴圈了n圈(1<=n)。假設slow走了s步,則 fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長為r,則:
2s = s + nr,簡化為 s= nr
s = x + y,x為鍊錶起點到環入口點的距離,y是slow在環內走過的距離;
可以得到 x = y - s = y - nr,從煉表頭、相遇點分別設乙個指標(p1, p2),每次各走一步,當p1走過距離x時到達入口點,而p2走過的距離為y-nr,y是相遇點與入口點的距離,因此y也走到了入口點,也就是說p1、p2在環入口點相遇了。
c**實現:
static listnode* findloopport(listnode *head)設定兩個指標(fast, slow),初始值都指向頭節點,slow每次前進一步,fast每次前進二步,當fast走到末尾時,slow剛好指向中間節點。if (fast == null || fast->next ==null)
return
null;
//找到環入口點
slow =head;
while (slow !=fast)
return
slow;
}
思路:用兩個指標,指標p1先走k-1步,然後指標p2才開始走,當指標p1遍歷完煉表時,p2還剩k個結點沒有遍歷。
實現如下:
listnode *findlastknode(listnode *head, int k)在鍊錶中刪除乙個結點,最常規的做法是遍歷鍊錶,找到要刪除的結點後再刪除,這種做法的時間複雜度是o(n);return t2; }
換一種思路,根據待刪除結點a,可以知道其下乙個結點是b=a->next,將結點b值拷貝給a,然後刪除b即可。
這種方法需要考慮一種特殊情況,a如果是尾結點,則b不存在,此時仍需要遍歷鍊錶一次。
c**實現:
void deletenode(listnode* head, listnode *pdel)方法一:從頭到尾遍歷鍊錶,每經過乙個結點的時候,把該結點放到乙個棧中;當遍歷完整個鍊錶後,再從棧頂開始輸出結點的值。else
}
該方法需要維護乙個額外的棧,實現起來比較麻煩。我們注意到遞迴本質上就是乙個棧結構,所以,也可以用遞迴來實現反向輸出鍊錶。
方法二:也就是說,每訪問到乙個結點的時候,先遞迴輸出它後面的結點,再輸出該結點自身。
c**實現:
void reverseprint(listnode *head)利用輔助指標就地修改節點的next域,**如下:printf(
"%d
", head->data);}}
static listnode *reverselist(listnode *head)遞迴 的實現方法:return
head;
}
static歸併排序實現的時間複雜度為 nlgn,void reverselist2(listnode**head)
struct listnode* merge(struct listnode* p1, struct listnode *p2)以上遞迴的實現會占用lgn的空間(遞迴壓棧),非遞迴的實現如下:else
}struct listnode* sortlist(struct listnode*head)
p->next =null;
h1 =sortlist(p1);
h2 =sortlist(head);
return
merge(h1, h2);
}
假設有乙個複雜鍊錶,它除了有乙個next指標外,還有乙個other指標,指向鍊錶中的任一結點或者null,
typedef struct如下圖,是乙個含義5個節點的該型別的複雜鍊錶,實線表示next指標,虛線表示other指標,null指標未標出。_listnode listnode;
最簡單的方法是,先複製所有節點,並用next指標鏈結起來,然後假設原始鍊錶的某節點n的other指標指向節點s,由於s的位置可能在n的前面,也可能在n的後面,所以要定位n的位置需要從原始鍊錶的頭節點開始找,直到確認節點s在鍊錶中的位置為s;然後在複製鍊錶上節點n的other指標也要指向距離煉表頭的第s個節點。這種方法的時間複雜度是o(n2)。
上面這種方法的主要缺點在於無法快速定位n節點的other所指向的s節點的位置,
下面將介紹一種時間複雜度是o(n)的方法,首先把複製的節點串到原節點後面,如下圖:
然後設定複製節點的other指標(例如 a'->other = a->other->next),如下圖
最後,把偶數順序的節點和奇數節點的指標分開。
//逐個節點複製,並串到原節點後面
static
void clonenodes(listnode *head)}//
設定新節點的other指標
static
void connectnodes(listnode *head)
p = pcloned->next;}}
經典鍊錶問題
題目描述 在單鏈表中輸出倒數第k個節點 要求 如果鍊錶長為n,時間複雜度為o n 額外空間複雜度達到o 1 思路 當我們用num來表示鍊錶中節點個數,當我們輸出節點的時候會出現三種情況 不存在第k個節點,此時返回空 num第k個節點就是第乙個節點,操作較容易 num k 第k個節點在鍊錶中 num ...
鍊錶經典問題彙總
原帖位址 收集了一下鍊錶常見的面試題 1 如何判斷乙個單鏈表有環 2 如何判斷乙個環的入口點在 3 如何知道環的長度 4 如何知道兩個單鏈表 無環 是否相交 5 如果兩個單鏈表 無環 相交,如何知道它們相交的第乙個節點是什麼 6 如何知道兩個單鏈表 有環 是否相交 7 如果兩個單鏈表 有環 相交,如...
鍊錶及經典問題
鍊錶及經典問題 鍊錶及經典問題 第一周 鍊錶及經典問題 1 鍊錶的基礎知識鍊錶的結構 訪問鍊錶的時間複雜度幾種經典的鍊錶實現方法 2 鍊錶的典型應用場景 3 經典面試題鍊錶的訪問鍊錶的反轉 鍊錶的節點刪除 4 彩蛋習題及相關說明 1 鍊錶的基礎知識 鍊錶的結構 節點資料域指標域 實現方式包括位址 下...