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

单链表之环形链表

[复制链接]
STMCU小助手 发布时间:2021-7-23 14:20
之前我的写文章《链表在STM32中的应用》6 Z. Q3 _+ `8 ]5 U+ D! u
# R  }- g- z# {& F* N2 H  Y# s: L/ B
! Y2 [" ^$ g# O$ o5 b+ u
    不论在面试或者刷题过程中,很大概率都会遇到环形链表这种类型的题目,例如 leetcode 141. 环形链表 以及 leetcode 142. 环形链表 II 等,本文主要介绍通过快慢指针法来解决此类题型,以供大家参考。2 B" ~/ d5 v" D2 W& l3 w

+ X" _& D1 D1 Q3 j

) R1 Z# e+ K! D4 D环形链表2 @- }3 W( S; u; ?
环形链表大致样子如下图所示:
5 ~- R  K6 ~2 ]% H* U( [9 K: b 1.jpg + z* k" u! \8 w; f
0 q5 d# k0 x4 x$ X1 }0 Q

, D4 d7 q& s1 _# b& N8 P快慢指针法* p: F8 }! J  D: ^7 F9 n/ w
判断链表是否是环形链表,一般通过快慢指针法。- U9 l: z& F5 {
, D" o) A; T+ g
# ^7 t) l8 U3 G) u- e- ?2 U
操作步骤
3 V+ T( W7 {7 `: K5 v  I: D一、分别定义两个均指向头节点的指针(fast/slow);+ C, Q0 y! Y5 K) W, {
二、快指针每次走两步,慢指针每次走一步;
# ?, h% N6 O7 a7 M5 a三、如果链表存在环,则快慢指针一定会在环中相遇。. v9 N( [4 D: |6 d& y
# d" z  _. y$ m  f9 |& m
! x9 r- x7 ^6 x6 v/ T7 P! m+ I! L& o' w
     如下图示,快慢指针行走的轨迹如下:; E2 K/ H: g( [1 t# G
faster:1--->3--->5--->7
3 [! F" w: E( K4 ^, l& xslower:1--->2--->3--->4" U, N/ H4 h2 @1 o! D' `
2.jpg
$ `* Z' K8 Y: R; `; ~faster:7--->5
! b! R) O) L7 f! Uslower:4--->5
9 p+ ~+ T) k& r' ?' q当他们同时到达节点 5 时,完美相遇。$ Y" z' v& c$ @4 g( b
3.jpg
, c! C9 D. e6 H3 F- U' ~" k% P, u: I" D4 @- s7 Z; S
& |: x) K! f* c9 o) o. }
举栗1:判断链表是否有环, a3 t4 m% q5 W, z
4.jpg
/ g4 n" j' ~8 N
题目

9 |/ Q7 c% K3 G3 C3 k5 \
Show me the Code
, h# y2 ^7 z- {- w% F& j
  1. <font face="微软雅黑" size="3">//  C 语言
    ' `/ x$ r7 q1 ~. V5 U+ u
  2. bool hasCycle(struct ListNode *head) {1 X: _4 ~& q! l3 y- E
  3.     /* 特判 */, l8 s# I5 B1 u% i7 g
  4.     if (head == NULL || head->next == NULL) {9 S1 |5 w. t6 a3 V" m" _, `5 `
  5.         return false;9 y4 v! n2 g, u1 `' t) \
  6.     }+ R- U" j6 s. T
  7.     struct ListNode *slow = head, *fast = head;+ G5 a9 l5 {8 q* d
  8.     /* fast指针走过链表末端,说明链表无环*/3 K7 l+ A& u3 _8 o# R
  9.     while((fast != NULL) && (fast->next != NULL)) {, W% K; |7 W3 Q9 K* R4 T) [  g! x5 t
  10.         slow = slow->next;
    5 ^0 E5 ]; e8 M) a
  11.         fast = fast->next->next;
    0 c- S1 N% S" E! A% m  c
  12.         if(slow == fast) {
    " M7 K3 `* ~) {2 X* Y1 ^
  13.             return true;! [3 ^, R' v' f' q8 h: j
  14.         }
    6 ~- |. L" t( ?  G4 O  U) B
  15.     }
    , a+ q/ X; k; P1 i' `* ~, Q
  16.     return false;
      B. L3 z) e0 b; W
  17. }</font>
复制代码
  1. <font face="微软雅黑" size="3"># python3" n0 j5 j0 o' V- t6 ?9 J
  2. class Solution:* h. _' f( o1 W
  3.     def hasCycle(self, head: ListNode) -> bool:' X8 ~, `) L3 I' L+ U) h9 ~" i
  4.         if not head or not head.next: return False     
    , ?, h9 k+ C3 W( A: h, Q+ A
  5.         slow, fast = head, head
    ' w* g5 @+ N- C1 p- z
  6.         while fast and fast.next:
    5 r9 x+ T. Q! d! P8 z/ [& h
  7.             slow = slow.next5 \" g7 c# I1 q, L4 W" J
  8.             fast = fast.next.next ) i  t' v6 a# b7 ^1 q; B6 x
  9.             if slow is fast: return True, Q7 d$ V% b( W" v) p% d( `  n; V
  10.         return False  </font>
复制代码
举例2:求入环的第一个节点4 z* ]. T$ Y7 ~
5.jpg ( E1 x# c4 J, `) y; B9 f6 U1 S6 w
题目

1 ^7 u: ?, G  A7 M, Z  E
/ _" k% |. t4 c1 a) {" a
思路
5 o" S1 {6 D" M本题除了需要判断链表是否有环外,如果有环还要求入环的第一个节点,因此是上一个题目的升级版本,还是以快慢指针中举例的那个链表作为示例,下图将描述当链表有环的时候,如何求出入环的第一个节点,见下图示:  s. d, t& N8 B$ @+ o  m
已判断链表有环; z+ @0 ]8 Q+ ?6 R! Y" k* n! j0 a
7.jpg
. |" Z( y3 ~# {6 f求入环的第一个节点
8 |' u* l5 b# a" w让慢指针重新指向链表的头节点,并让快慢指针同时每次只走一步; [  o: p4 X5 l9 [0 |4 ~' z
faster:5--->6--->7
) s( ^3 n% R! g* e$ Q9 t; Y2 \slower:1--->2--->3
' n6 x' {3 |7 |9 d4 F! O3 E- B 8.jpg
8 d$ M. o# E- `0 X7 p继续走
  H7 X5 ]: u% F: e2 v. f7 x% R3 Wfaster:7--->4( K4 g' C- j/ F2 |/ t* L# ]
slower:3--->45 b& v0 C2 [- \3 s: X/ X: [
当他们同时到达节点 4 时,再次完美相遇。# ~! O3 y8 f0 |& e0 l5 A
9.jpg
  c. i8 b- E3 D" L6 r$ v5 a% K+ y9 l+ U1 |7 m  h! f+ o

8 D# ]3 E. m4 {2 U, |0 P+ S3 M& w6 ^; \

4 u$ v( A. ?/ j6 V- A因此,由上面的图可知,当判断链表有环(快慢指针相遇)之后,再让快(或者慢)指针重新指向链表头节点,另外一个指针仍保持指向不变,然后让快/慢指针同时走,且每次只走一步,当他们再次相遇时,此时相遇的节点就是入环的第一个节点。
' {$ c6 [  z/ i9 z6 ?. M; \! j% V6 A! Y0 D# l- u5 R

% ^/ r& w" K" DShow me the Code
/ U# J  }" q0 T$ n5 K2 b0 `
  1. <font face="微软雅黑" size="3">//  c 语言
      V6 y3 q8 j0 {8 A, `
  2. struct ListNode *detectCycle(struct ListNode *head) {' E5 T9 f3 o1 g! P1 ?
  3.     /* 记录是否有环 */! e" s; j5 Z6 ]
  4.     bool flag = false;  
    ( J+ t7 V5 N& X+ Y
  5.     struct ListNode *slow = head, *fast = head;
    : H/ B+ ^! k/ e. n8 c3 M7 v1 S
  6.     while (fast != NULL && fast->next != NULL) {
    8 [" h1 \* o8 G* ~) i9 F# u" A
  7.         slow = slow->next;
    ' f% h" V  e% m( O7 W
  8.         fast = fast->next->next;
    ( y; `4 r. N  w
  9.         /* 有环则更新 flag 的值,并跳出循环寻找入环第一个节点 */' y, I( ]( M% W1 g3 _
  10.         if (slow == fast) {, F; q: w2 v- W
  11.             flag = true;
    / r' }. |& Z; a7 z/ Y5 A# m0 r* {5 B
  12.             break;, {/ q$ Y% ?5 B4 q/ j
  13.         }
    5 c2 w( K" J. h# ~( Q
  14.     }. b6 m6 c# {  h
  15.     /* 无环则直接返回空 */
    . \" U5 g/ r7 f! z$ ^; K
  16.     if (flag == false) {
    8 ~. K+ M! L$ G' d0 k; [
  17.         return NULL;
    & F( o8 D- d: Q- y
  18.     }: ^, X+ n; ^: Q& s9 ?7 e
  19.     /* 慢指针重新指向链表头节点,快指针仍指向相遇节点 */
    : X2 ]: I+ K) b, X2 j
  20.     slow = head;
    , @% O$ Z& A: h# V
  21.     /* 快慢指针每次走一步,相遇节点即为入环第一个节点 *// o" q* [- D0 \9 r7 D! A
  22.     while (fast != slow) {
    4 j9 |- H7 n" W9 J5 |
  23.         fast = fast->next;& h1 }$ }- J9 a8 n
  24.         slow = slow->next;
    - {2 \2 N& t% n, T1 Q
  25.     }# O+ A& b, K( F- P, b
  26.     return slow;, q; X$ s  V7 f$ T
  27. }</font>
复制代码
  1. <font face="微软雅黑" size="3">//  go 语言+ }9 V/ I' ]- q# _. j) M+ s

  2. # W) u9 F! p  u) X
  3. func detectCycle(head *ListNode) *ListNode {. C7 P, f+ R# p2 _7 @! v
  4.     slow, fast := head, head
    ! _" h) S) V8 {/ Y. l5 l3 l
  5.     for fast != nil && fast.Next != nil {" p, s7 S+ `+ x4 g
  6.         fast, slow = fast.Next.Next, slow.Next
    , A& C2 j. k& j! H
  7.         if fast == slow {  \! `  c3 F/ r) I/ V
  8.             break' V8 h& W( \; X
  9.         }
    2 l2 X: }6 X+ p2 ?5 T. ~' Y
  10.     }
      u6 R4 X. b2 S7 [. C1 k
  11.     if fast == nil || fast.Next == nil {
    3 p! A: x2 v) P1 U: _
  12.         return nil
    $ I' u/ y' o) Z7 g& E. m
  13.     }( Z0 @9 m7 z' T5 z6 L1 @3 H
  14.     slow = head
    6 e! M& ?4 }8 l" |$ o
  15.     for fast != slow {, h1 I- h8 X" b
  16.         fast, slow = fast.Next, slow.Next
    ) G$ j* [: _+ H) k2 K
  17.     }
    % ]' W* t; N/ ~. @
  18.     return fast
    ! M4 s& u' I9 D2 u
  19. }</font>
复制代码
- [9 S! H  e# n  @! Y' j3 ]

& S6 J3 e% T3 V( R/ @( z( d
6.jpg
收藏 评论0 发布时间:2021-7-23 14:20

举报

0个回答

所属标签

相似分享

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