你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

单链表之环形链表

[复制链接]
STMCU小助手 发布时间:2021-7-23 14:20
之前我的写文章《链表在STM32中的应用》2 K( [& w& c) Z

! E/ b8 L& a' x& ~. ?( c
' Z. o" ~" h% m% |' O9 g
    不论在面试或者刷题过程中,很大概率都会遇到环形链表这种类型的题目,例如 leetcode 141. 环形链表 以及 leetcode 142. 环形链表 II 等,本文主要介绍通过快慢指针法来解决此类题型,以供大家参考。
9 g- P: f: A. I# o. w/ m* K3 u0 Y9 D7 C# B9 M% f/ ^/ R
  F' X' Q; P! K* G) t
环形链表0 }/ v& z5 ]  _# m" q: R# ?
环形链表大致样子如下图所示:/ [4 \( a) q' t. l; N+ |: p& b
1.jpg $ F( j1 D# s+ I

( [% [; }3 T5 \& f" F! ?
8 f3 U! g% ]1 r- k9 x2 o* `& O' A2 V快慢指针法  i+ k6 _; v9 K, g
判断链表是否是环形链表,一般通过快慢指针法。1 L! ?+ z# w  ]* x
. u! X  p5 _+ Z. w# R( a3 a+ }" L

* A) |5 N' b: z: m$ p! U操作步骤
; `$ D8 s3 t* g& U1 `4 v一、分别定义两个均指向头节点的指针(fast/slow);+ @+ A$ F% V, }. a# C& _
二、快指针每次走两步,慢指针每次走一步;
. H$ }! J- |: k& }# C; e6 L三、如果链表存在环,则快慢指针一定会在环中相遇。2 L# O, k! {- V* k( i

7 t* A. h2 s; Z) z2 H8 |+ A: t: l
* v; h7 X7 T! g& C2 Y
     如下图示,快慢指针行走的轨迹如下:. V2 T  t1 n( f& h7 o( H
faster:1--->3--->5--->7- V1 |5 M6 k& q1 s- \, ^
slower:1--->2--->3--->4; w+ @0 k% @( l6 h6 m3 {2 o
2.jpg
1 b  Z2 d: `2 V& G; `faster:7--->57 w, j5 ~1 G+ c7 @* K, W# A6 Q7 t
slower:4--->5
& o8 V2 W7 l$ V, D当他们同时到达节点 5 时,完美相遇。: t% V( q; b# v# R5 W- `( O
3.jpg
" [- F9 o0 f" c. ?
0 s. s0 W1 ?/ q" C8 v2 H9 x9 i

0 e9 \3 i( M1 L6 r! r举栗1:判断链表是否有环
1 ?. A1 W2 [4 c6 G7 f' y: i 4.jpg 8 k$ E$ i4 y; }! `# u
题目
2 H* X6 h  q1 K
Show me the Code
6 e: M/ E4 `" [$ Z$ m' S
  1. <font face="微软雅黑" size="3">//  C 语言
    " v1 Z5 |- n% S$ F; M1 R: A
  2. bool hasCycle(struct ListNode *head) {
    & h6 Z' ~) g- @0 `
  3.     /* 特判 */
    / z1 y0 j, Q2 a% g9 `! ]
  4.     if (head == NULL || head->next == NULL) {
    ! h% W" D6 [1 c) @8 P' }
  5.         return false;$ v+ d2 t; {0 _. D  l3 ]
  6.     }
    ! d2 L. x9 v) I+ M9 d9 B1 Q
  7.     struct ListNode *slow = head, *fast = head;% m5 X6 f" j) y
  8.     /* fast指针走过链表末端,说明链表无环*/
    ) z/ ^+ K0 C5 Q! c" M
  9.     while((fast != NULL) && (fast->next != NULL)) {
    ; `) t( |$ L0 o0 g$ U
  10.         slow = slow->next;# K* [8 v2 m- F; U+ _- \4 Y" H
  11.         fast = fast->next->next;
    ) A* }& b8 |* X$ g$ `
  12.         if(slow == fast) {! F8 U, h& D5 v# P. H! t1 W7 Q/ W) G  x/ ~5 C
  13.             return true;
    9 @0 X5 y. G/ [
  14.         }
    + c- }  ]# n+ O0 Q4 e2 ?, I
  15.     }3 g6 y$ e+ m1 K! p. E/ n
  16.     return false;% A2 {  D3 W: ^  U0 n! `  \& D
  17. }</font>
复制代码
  1. <font face="微软雅黑" size="3"># python3
    5 K, s5 D- ?2 N0 E$ {/ [& S, r
  2. class Solution:) R% {5 v( U6 ]& V
  3.     def hasCycle(self, head: ListNode) -> bool:
    1 f5 z2 G5 S4 D( P+ \
  4.         if not head or not head.next: return False     * g- i, ^* m! h+ Q! x
  5.         slow, fast = head, head
    , L" K6 x$ L- h) l9 W8 ]0 v) F
  6.         while fast and fast.next:( l4 I2 Z" H" H3 g
  7.             slow = slow.next, t# m7 H+ m. z. \
  8.             fast = fast.next.next , a- N" g, R1 `8 E- H* `9 X% h0 o
  9.             if slow is fast: return True# H1 R3 }. [2 ^+ q2 S
  10.         return False  </font>
复制代码
举例2:求入环的第一个节点
% o2 A3 t' M; _* L4 y- D5 a; \+ \ 5.jpg " [3 A4 q) ~0 K: R& C
题目
. J, r9 t- Y: |2 h" }, c. x

5 h' q- ]9 m: l% Z% X% z& p思路
; d/ i4 k& Y( o# B' i本题除了需要判断链表是否有环外,如果有环还要求入环的第一个节点,因此是上一个题目的升级版本,还是以快慢指针中举例的那个链表作为示例,下图将描述当链表有环的时候,如何求出入环的第一个节点,见下图示:
/ |/ M* m3 R* W$ T6 o已判断链表有环
7 M* _" r/ ?( ~! l" q4 b. E  k8 J/ j 7.jpg
0 N1 _9 [# j# a. Z) R求入环的第一个节点
4 q1 p/ H9 N) j3 l; e6 {' U, @让慢指针重新指向链表的头节点,并让快慢指针同时每次只走一步
& b9 d  @- a. Q$ ~; I, a& Z: Kfaster:5--->6--->7
; ~5 V! n! @( qslower:1--->2--->3
/ c6 V+ \8 _2 a5 h3 @ 8.jpg
  \: z$ G1 t. y% O% ?3 Y  o1 b继续走
6 i5 F8 b# _( u# U# ffaster:7--->4
6 ~# C4 M3 r  g; J. [3 Y0 i% fslower:3--->4
: u8 e$ l- u/ O当他们同时到达节点 4 时,再次完美相遇。
; Y0 e# C, `0 u$ a 9.jpg
- o6 V$ c1 T8 m! N' D' a. h4 a
* X: n( F+ z, w! f
" D3 s; ~" F4 v) o! V" o
( \9 N# D- }. c: A7 F% ^

0 H  d0 t" ~! ^7 o& M因此,由上面的图可知,当判断链表有环(快慢指针相遇)之后,再让快(或者慢)指针重新指向链表头节点,另外一个指针仍保持指向不变,然后让快/慢指针同时走,且每次只走一步,当他们再次相遇时,此时相遇的节点就是入环的第一个节点。
7 E! {0 Q+ {, X! u0 g6 H' f% A9 `. m; D- [

1 }. q7 G, R0 s8 t+ G2 g" U7 N2 UShow me the Code
1 T! M. ~8 F1 U" r9 l  U' D1 Q0 ^; i
  1. <font face="微软雅黑" size="3">//  c 语言6 p/ |1 q) B: p0 q% b
  2. struct ListNode *detectCycle(struct ListNode *head) {8 d3 A2 J* C. j4 z% A6 p' V
  3.     /* 记录是否有环 */
    3 ^2 d! h; N) |! @
  4.     bool flag = false;  
    ( Q, i0 j* S& G! w) v
  5.     struct ListNode *slow = head, *fast = head;( j- e0 {+ h& r/ O4 L
  6.     while (fast != NULL && fast->next != NULL) {' Q5 G8 L8 c2 ^% Q, ]. W: i$ J
  7.         slow = slow->next;9 @+ h  o1 O* r$ B6 C- G
  8.         fast = fast->next->next;$ F  R+ H3 t* ^5 F+ [# m( }9 K
  9.         /* 有环则更新 flag 的值,并跳出循环寻找入环第一个节点 */
    / ^9 R7 j$ `1 k" q9 R
  10.         if (slow == fast) {8 x# d3 {9 S# [: r: W
  11.             flag = true;
      X# ?1 h, K: U1 ~/ |: ^9 d
  12.             break;
    3 B3 P1 l0 W! _# n( }) F3 V* F
  13.         }
    6 o9 g) g) I4 L& `  o9 I
  14.     }9 Y1 @& j5 B% Y1 k4 p/ ^* S/ z
  15.     /* 无环则直接返回空 */
    ' ]5 |; A. g# z. N% p+ ~2 e
  16.     if (flag == false) {; B$ [& `; A" S% H, r3 @- Q
  17.         return NULL;
    4 f- h; f; R" s" K
  18.     }
    # j7 a# a* ?1 k0 M
  19.     /* 慢指针重新指向链表头节点,快指针仍指向相遇节点 */  b% Y0 S  y; K0 [
  20.     slow = head;# L( p4 @( M' Z9 O3 S: D
  21.     /* 快慢指针每次走一步,相遇节点即为入环第一个节点 */
    : y% R, W$ ]5 U: a
  22.     while (fast != slow) {  U/ k, R0 v. u. `3 H7 q
  23.         fast = fast->next;6 k( ~! f% l- G4 {
  24.         slow = slow->next;1 D0 v  K5 V: k4 I4 f+ P
  25.     }
    , t5 p& k  w& [3 N
  26.     return slow;* Y; H# K; n; V& O- M; J1 D# f
  27. }</font>
复制代码
  1. <font face="微软雅黑" size="3">//  go 语言0 ~$ I! b9 X2 m. H# {% U
  2. " O  a; V0 b5 z% x, m. q2 M2 ?
  3. func detectCycle(head *ListNode) *ListNode {
    & D; O- U& r4 g( J  J( z
  4.     slow, fast := head, head
    & \* O9 C( O3 [1 h/ _
  5.     for fast != nil && fast.Next != nil {
    . @) v. K* J% A1 \$ s+ x! t- m
  6.         fast, slow = fast.Next.Next, slow.Next
    9 i; ]% {+ ~2 L9 @* m2 v
  7.         if fast == slow {+ S1 U- _1 _6 k$ w: X
  8.             break
    ( M' H9 i; ^8 Q2 `
  9.         }
    5 D4 v6 Z: w& }. A: d
  10.     }
    6 m* I+ M0 q9 S
  11.     if fast == nil || fast.Next == nil {- E; _6 _: @+ i0 j
  12.         return nil
    3 H4 c" K; t$ F4 u- N
  13.     }
    0 Q, a" c! H; x8 y- I- e7 O& F! W
  14.     slow = head$ W3 n. J* R* U1 _
  15.     for fast != slow {
    9 w( r3 x. p. z9 D' V9 j4 [
  16.         fast, slow = fast.Next, slow.Next
    0 U6 @; |, b& e2 q1 W: ~  U
  17.     }
    1 ]2 ]. |$ l2 |( b
  18.     return fast5 d; [% [3 F  F/ a* w# T
  19. }</font>
复制代码
2 s! Z, u' v4 }0 o, O
- {8 p& I* p8 B; l) z' J3 g5 M
6.jpg
收藏 评论0 发布时间:2021-7-23 14:20

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版