0Pricing
Coding Interview Prep · บทเรียน

การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร

ตรวจจับเส้นเชื่อมที่ทำให้เกิดวงจรในกราฟไม่มีทิศทางด้วยการรวมแต่ละเส้นเชื่อม และตรวจสอบว่าโหนดสองตัวเชื่อมโยงกันอยู่แล้วหรือไม่

การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร เป็นบทเรียน Coding Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Coding Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

เส้นเชื่อมเกินคืออะไร

ปัญหา เส้นเชื่อมเกิน (LeetCode 684) ให้ต้นไม้ที่มีโหนด n โหนดและเส้นเชื่อมเกินมาอีกหนึ่งเส้น ซึ่งทำให้เกิดวัฏจักรเพียงหนึ่งวัฏจักร หน้าที่ของคุณคือค้นหาเส้นเชื่อมที่เมื่อลบออกแล้วจะทำให้ต้นไม้กลับมาเป็นต้นไม้ที่ถูกต้อง หากมีคำตอบหลายรายการ ให้ส่งคืนรายการสุดท้ายในรายการข้อมูลเข้า

ต้นไม้ที่มีโหนด n โหนดจะมีเส้นเชื่อมทั้งหมด n-1 เส้น เชื่อมต่อถึงกัน และไม่มีวัฏจักร การเพิ่มเส้นเชื่อมอีกหนึ่งเส้นจะสร้างวัฏจักรขึ้นมาเพียงหนึ่งวัฏจักร เส้นเชื่อมที่เพิ่มเข้ามา (เส้นเชื่อมเกิน) จะเชื่อมโหนดสองโหนดที่อยู่ในองค์ประกอบเดียวกันอยู่แล้ว ซึ่งเป็นสถานการณ์คลาสสิกสำหรับการตรวจจับวัฏจักรด้วย DSU

# Example
# n=5, edges = [[1,2],[1,3],[2,3],[2,4],[3,5]]
# Adding edge [2,3] creates cycle 1-2-3-1
# So [2,3] is the redundant connection

# Key insight: process edges one by one with DSU
# The FIRST edge where both endpoints are already connected is the redundant one
print('Tree property: n nodes, n-1 edges, no cycles')
print('Adding 1 edge: n nodes, n edges, exactly 1 cycle')
print('DSU approach: find the edge that connects already-connected nodes')

การตรวจจับวัฏจักรด้วย DSU

DSU ตรวจจับวัฏจักรได้โดยธรรมชาติ: ก่อนเพิ่มเส้นเชื่อม (u, v) ให้ตรวจสอบว่า find(u) == find(v) หรือไม่ หากทั้งสองโหนดมีรากเดียวกัน แสดงว่าเชื่อมต่อกันอยู่แล้ว — การเพิ่มเส้นเชื่อมนี้จะสร้างวัฏจักร เส้นเชื่อมนี้คือ เส้นเชื่อมเกิน

วิธีนี้ใช้ได้กับกราฟไม่มีทิศทาง สำหรับเส้นเชื่อมแต่ละเส้น เราอาจ union องค์ประกอบทั้งสองได้สำเร็จ (ยังไม่เกิดวัฏจักร) หรือตรวจพบว่าปลายทั้งสองอยู่ในองค์ประกอบเดียวกันอยู่แล้ว (พบวัฏจักร) ความซับซ้อนด้านเวลาคือ O(n × alpha(n)) ซึ่งเกือบเท่ากับ O(n)

def find_redundant_connection(edges):
    n = len(edges)
    parent = list(range(n + 1))  # 1-indexed
    rank = [0] * (n + 1)

    def find(x):
        if parent[x] != x:
            parent[x] = find(parent[x])
        return parent[x]

    def union(x, y):
        px, py = find(x), find(y)
        if px == py:
            return False           # same component => cycle found
        if rank[px] < rank[py]: px, py = py, px
        parent[py] = px
        if rank[px] == rank[py]: rank[px] += 1
        return True

    for u, v in edges:
        if not union(u, v):
            return [u, v]     # this edge creates the cycle

edges = [[1,2],[1,3],[2,3],[2,4],[3,5]]
print(find_redundant_connection(edges))  # [2, 3]

การติดตามการทำงานของอัลกอริทึม

ลองติดตาม [[1,2],[1,3],[2,3]] ทีละขั้นตอน ในตอนเริ่มต้น แต่ละโหนดเป็นองค์ประกอบของตัวเอง: {1}, {2}, {3}

  • เส้นเชื่อม [1,2]: find(1)=1, find(2)=2, แตกต่างกัน — union โหนดทั้งสอง องค์ประกอบ: {1,2}, {3}
  • เส้นเชื่อม [1,3]: find(1)=ราก, find(3)=3, แตกต่างกัน — union โหนดทั้งสอง องค์ประกอบ: {1,2,3}
  • เส้นเชื่อม [2,3]: find(2)=ราก, find(3)=ราก — รากเดียวกัน! ตรวจพบวัฏจักร ส่งคืน [2,3]

อัลกอริทึมประมวลผลเส้นเชื่อมตามลำดับและส่งคืนเส้นเชื่อมแรกที่ทำให้เกิดวัฏจักร เนื่องจากปัญหานี้รับประกันว่ามีเส้นเชื่อมเกินเพียงหนึ่งเส้น เส้นเชื่อมนี้จึงเป็นเส้นเชื่อมเกินที่ถูกต้องเสมอ

def find_redundant_trace(edges):
    parent = list(range(len(edges) + 1))

    def find(x):
        while parent[x] != x:
            parent[x] = parent[parent[x]]
            x = parent[x]
        return x

    for u, v in edges:
        pu, pv = find(u), find(v)
        print(f'Edge ({u},{v}): find({u})={pu}, find({v})={pv}', end=' => ')
        if pu == pv:
            print('CYCLE DETECTED!')
            return [u, v]
        parent[pv] = pu
        print('merged')
    return []

result = find_redundant_trace([[1,2],[1,3],[2,3]])
print('Redundant edge:', result)

การตรวจจับวัฏจักรในกราฟไม่มีทิศทางด้วย DFS

ทางเลือกอื่นนอกเหนือจาก DSU สำหรับตรวจจับวัฏจักรในกราฟไม่มีทิศทางคือ DFS พร้อมการติดตามโหนดแม่ ระหว่างทำ DFS หากเราไปถึงโหนดที่เคยเยี่ยมชมแล้วและโหนดนั้นไม่ใช่โหนดแม่โดยตรงของโหนดปัจจุบัน แสดงว่าเราพบเส้นเชื่อมย้อนกลับ ซึ่งบ่งชี้ว่ามีวัฏจักร

อย่างไรก็ตาม วิธี DFS ต้องใช้เวลา O(V + E) และบอกได้ว่ามีวัฏจักรหรือไม่ แต่ไม่สามารถระบุได้ง่ายว่าเส้นเชื่อมใดเป็นเส้นเชื่อมเกิน DSU จึงเหมาะกว่าสำหรับปัญหาที่ขอให้ระบุเส้นเชื่อมเกินโดยเฉพาะ เพราะเราจะพบเส้นเชื่อมนั้นโดยธรรมชาติเมื่อการ union ล้มเหลว

from collections import defaultdict

def has_cycle_dfs(n, edges):
    graph = defaultdict(list)
    for u, v in edges:
        graph[u].append(v)
        graph[v].append(u)

    visited = set()

    def dfs(node, parent):
        visited.add(node)
        for nb in graph[node]:
            if nb == parent:
                continue           # skip the edge we came from
            if nb in visited:
                return True        # back edge => cycle
            if dfs(nb, node):
                return True
        return False

    for node in range(1, n + 1):
        if node not in visited:
            if dfs(node, -1):
                return True
    return False

print(has_cycle_dfs(3, [[1,2],[1,3],[2,3]]))  # True
print(has_cycle_dfs(3, [[1,2],[1,3]]))        # False

การตรวจจับวัฏจักรในกราฟมีทิศทาง

สำหรับ กราฟมีทิศทาง การตรวจจับวัฏจักรด้วย DSU ไม่สามารถใช้ได้โดยตรง เนื่องจากเส้นเชื่อมมีทิศทาง ให้ใช้ DFS พร้อมการทำเครื่องหมายสามสี แทน ได้แก่ สีขาว (ยังไม่เยี่ยมชม) สีเทา (อยู่ในเส้นทาง DFS ปัจจุบัน) และสีดำ (ประมวลผลเสร็จสมบูรณ์) เส้นเชื่อมย้อนกลับไปยังโหนดสีเทาบ่งชี้ว่ามีวัฏจักร

ในกราฟไม่มีทิศทาง เส้นเชื่อมย้อนกลับใด ๆ ก็หมายถึงมีวัฏจักร แต่ในกราฟมีทิศทาง เส้นเชื่อมข้ามไปยังโหนดสีดำไม่ใช่วัฏจักร — มีเพียงเส้นเชื่อมย้อนกลับไปยังโหนดสีเทาเท่านั้นที่เป็นวัฏจักร ความแตกต่างนี้สำคัญมากและมีการทดสอบในปัญหาจัดตารางรายวิชา

def has_cycle_directed(n, edges):
    graph = defaultdict(list)
    for u, v in edges:
        graph[u].append(v)

    # 0=white(unvisited), 1=grey(in stack), 2=black(done)
    color = [0] * (n + 1)

    def dfs(node):
        color[node] = 1            # grey: currently visiting
        for nb in graph[node]:
            if color[nb] == 1:
                return True        # back edge to grey node => cycle
            if color[nb] == 0:
                if dfs(nb):
                    return True
        color[node] = 2            # black: fully processed
        return False

    for node in range(1, n + 1):
        if color[node] == 0:
            if dfs(node):
                return True
    return False

from collections import defaultdict
print(has_cycle_directed(3, [[1,2],[2,3],[3,1]]))  # True: 1->2->3->1
print(has_cycle_directed(3, [[1,2],[1,3],[2,3]]))  # False

เส้นเชื่อมเกิน II: รูปแบบกราฟมีทิศทาง

LeetCode 685 ขยายปัญหาไปสู่กราฟมีทิศทางที่แต่ละโหนดมีโหนดแม่เพียงหนึ่งโหนด (เป็นต้นไม้ที่มีรากและมีเส้นเชื่อมเกินอีกหนึ่งเส้น) มีสองกรณีที่อาจเกิดขึ้น ได้แก่ โหนดหนึ่งมีโหนดแม่สองโหนด (ดีกรีขาเข้าเป็น 2) หรือมีวัฏจักรโดยไม่มีโหนดใดมีโหนดแม่สองโหนด

วิธีแก้จะตรวจหาโหนดที่มีดีกรีขาเข้าเป็น 2 ก่อน หากพบ เส้นเชื่อมขาเข้าเส้นใดเส้นหนึ่งจากสองเส้นนั้นต้องเป็นคำตอบ จากนั้นใช้การตรวจจับวัฏจักรด้วย DSU เพื่อพิจารณาว่าควรลบเส้นเชื่อมตัวเลือกใด วิธีแบบสองระยะนี้จัดการได้ถูกต้องในทุกกรณี

def find_redundant_directed(edges):
    n = len(edges)
    parent_map = {}          # node -> its parent in the input
    candidate1 = candidate2 = None

    for u, v in edges:
        if v in parent_map:                # v already has a parent
            candidate1 = [parent_map[v], v]  # earlier edge
            candidate2 = [u, v]              # later edge
        else:
            parent_map[v] = u

    # DSU cycle detection, skipping candidate2 if it exists
    dsu = list(range(n + 1))
    def find(x):
        while dsu[x] != x: dsu[x] = dsu[dsu[x]]; x = dsu[x]
        return x
    def union(x, y):
        px, py = find(x), find(y)
        if px == py: return False
        dsu[px] = py; return True

    for u, v in edges:
        if candidate2 and [u, v] == candidate2: continue   # skip candidate2
        if not union(u, v):              # cycle found without candidate2
            return candidate1 if candidate1 else [u, v]

    return candidate2   # no cycle when excluding candidate2 => candidate2 is redundant

print(find_redundant_directed([[1,2],[1,3],[2,3]]))  # [2,3]
print(find_redundant_directed([[1,2],[2,3],[3,4],[4,1],[1,5]]))  # [4,1]

การตรวจสอบความถูกต้องของกราฟหลังลบเส้นเชื่อม

หลังจากระบุเส้นเชื่อมเกินแล้ว เราสามารถตรวจสอบผลลัพธ์ได้โดยดูว่าการลบเส้นเชื่อมนั้นทำให้เหลือต้นไม้ที่ถูกต้องหรือไม่: มีเส้นเชื่อม n-1 เส้นพอดี โหนดทั้งหมดเชื่อมต่อกัน และไม่มีวัฏจักร สำหรับปัญหาสัมภาษณ์นี้ DSU รับประกันคุณสมบัติดังกล่าวโดยธรรมชาติ — หากเราส่งคืนเส้นเชื่อมที่ทำให้การ union ล้มเหลว เมื่อลบเส้นเชื่อมนั้น เราจะเหลือเส้นเชื่อม n-1 เส้นที่ union สำเร็จพอดี และเส้นเชื่อมเหล่านั้นจะประกอบกันเป็นต้นไม้ทอดข้าม

การรับประกันนี้เป็นเหตุผลที่ DSU เหมาะสมกับปัญหานี้มาก: การ union ที่สำเร็จจะสร้างต้นไม้ทีละขั้น และการ union ที่ล้มเหลวจะระบุเส้นเชื่อมหนึ่งเส้นที่ไม่ควรอยู่ในต้นไม้

def verify_tree(n, edges, removed_edge):
    parent = list(range(n + 1))

    def find(x):
        while parent[x] != x:
            parent[x] = parent[parent[x]]
            x = parent[x]
        return x

    components = n
    for u, v in edges:
        if [u, v] == removed_edge:
            continue         # skip the removed edge
        pu, pv = find(u), find(v)
        if pu == pv:
            print('CYCLE DETECTED after removal! Wrong answer.')
            return False
        parent[pv] = pu
        components -= 1

    if components != 1:
        print(f'Graph not connected ({components} components). Wrong answer.')
        return False
    print('Valid tree after removing edge:', removed_edge)
    return True

edges = [[1,2],[1,3],[2,3]]
verify_tree(3, edges, [2,3])
verify_tree(3, edges, [1,2])  # wrong removal

การวิเคราะห์ความซับซ้อนด้านเวลาและพื้นที่

วิธีแก้ปัญหาเส้นเชื่อมเกินด้วย DSU จะประมวลผลเส้นเชื่อมทั้ง n เส้นครั้งละหนึ่งครั้ง และการดำเนินการ union/find แต่ละครั้งใช้เวลา O(alpha(n)) แบบเฉลี่ยสะสม เวลารวมคือ O(n × alpha(n)) ซึ่งในทางปฏิบัติเท่ากับ O(n)

ความซับซ้อนด้านพื้นที่คือ O(n) สำหรับอาร์เรย์โหนดแม่และอันดับ วิธีนี้เหมาะสมที่สุดแล้ว — อย่างน้อยคุณต้องอ่านเส้นเชื่อมทั้ง n เส้นและจัดเก็บสถานะบางส่วนสำหรับแต่ละโหนด ลองเปรียบเทียบกับวิธีพื้นฐานที่เรียกใช้ DFS หลังการเพิ่มเส้นเชื่อมแต่ละเส้น: ใช้เวลา O(n²) และพื้นที่ O(n + E)

# Summary of complexities
complexity = {
    'Naive (DFS after each edge)': {'time': 'O(n^2)', 'space': 'O(n)'},
    'DSU (path compression + rank)': {'time': 'O(n * alpha(n))', 'space': 'O(n)'},
    'Sorting + DSU (Kruskal style)': {'time': 'O(n log n)', 'space': 'O(n)'},
}
for approach, costs in complexity.items():
    print(f'{approach}:')
    print(f'  Time:  {costs["time"]}')
    print(f'  Space: {costs["space"]}')
    print()
print('alpha(n) <= 4 for all practical n, so DSU is effectively O(n).')

กรณีขอบ: เส้นเชื่อมวนกลับหาตัวเอง

เส้นเชื่อมวนกลับหาตัวเอง [u, u] จะสร้างวัฏจักรทันที เนื่องจากปลายทั้งสองคือโหนดเดียวกัน ใน DSU find(u) == find(u) เป็นจริงเสมอ ดังนั้นการ union จึงล้มเหลวทันที และ [u, u] จะถูกส่งคืนเป็นเส้นเชื่อมเกิน

เงื่อนไขของปัญหาส่วนใหญ่รับประกันว่าจะไม่มีเส้นเชื่อมวนกลับหาตัวเอง แต่โค้ดที่รัดกุมควรรองรับกรณีนี้ การทำงานของ DSU รองรับกรณีนี้ได้โดยธรรมชาติโดยไม่ต้องมีกรณีพิเศษ — การตรวจสอบวัฏจักร if find(u) == find(v) จะตรวจพบก่อนที่จะพยายามทำ union เสมอ โปรดตรวจสอบด้วยข้อมูลเข้ากรณีขอบ เช่น เส้นเชื่อมวนกลับหาตัวเองในกราฟที่มีโหนดเดียวและข้อมูลเข้าขนาดต่ำสุด

def find_redundant_robust(edges):
    n = len(edges)
    parent = list(range(n + 1))

    def find(x):
        if parent[x] != x:
            parent[x] = find(parent[x])
        return parent[x]

    for u, v in edges:
        pu, pv = find(u), find(v)
        if pu == pv:
            return [u, v]   # handles self-loops too: u==v => pu==pv always
        parent[pv] = pu
    return []

# Self-loop test
print(find_redundant_robust([[1,2],[2,2]]))    # [2,2] self-loop
# Minimum tree test
print(find_redundant_robust([[1,2],[2,3],[1,3]]))  # [1,3]
# Standard test
print(find_redundant_robust([[1,2],[1,3],[2,3],[2,4],[3,5]]))  # [2,3]

การประยุกต์ใช้การตรวจจับวัฏจักรกับอัลกอริทึมต่าง ๆ

มีอัลกอริทึมหลายแบบที่ใช้ตรวจจับวัฏจักร โดยแต่ละแบบเหมาะกับสถานการณ์แตกต่างกัน:

  • DSU: กราฟไม่มีทิศทาง เส้นเชื่อมเข้ามาแบบออนไลน์ ใช้เวลา O(alpha(n)) ต่อเส้นเชื่อม — เหมาะที่สุดสำหรับการนับหรือค้นหาเส้นเชื่อมเกิน
  • DFS พร้อมการติดตามโหนดแม่: กราฟไม่มีทิศทาง รู้เส้นเชื่อมทั้งหมดตั้งแต่ต้น ใช้เวลา O(V+E) — เหมาะที่สุดเมื่อต้องการเส้นทางของวัฏจักร
  • DFS แบบสามสี: กราฟมีทิศทาง ใช้ตรวจหาเส้นเชื่อมย้อนกลับ ใช้เวลา O(V+E) — เหมาะที่สุดสำหรับปัญหาจัดตารางรายวิชาและการเรียงลำดับเชิงทอพอโลยี
  • การเรียงลำดับเชิงทอพอโลยี (ของ Kahn): กราฟมีทิศทาง ตรวจจับวัฏจักรผ่านโหนดที่มีดีกรีขาเข้าไม่เป็นศูนย์ซึ่งเหลืออยู่ — เหมาะที่สุดเมื่อต้องการการจัดลำดับด้วย
# When to use which cycle-detection method:
# Problem type => preferred algorithm

problems = [
    ('Redundant Connection (undirected)', 'DSU'),
    ('Course Schedule (directed)', 'DFS three-color or Kahn topological sort'),
    ('Detect cycle in undirected graph', 'DFS with parent tracking or DSU'),
    ('Find cycle members in directed graph', 'DFS three-color + backtrack'),
    ('Online graph edges with cycle check', 'DSU'),
    ('Minimum spanning tree validity', 'DSU (Kruskal)'),
]
for problem, solution in problems:
    print(f'{problem}\n  => {solution}\n')

วิธีแก้ปัญหาฉบับสมบูรณ์พร้อมกรณีขอบ

นี่คือวิธีแก้ปัญหาเส้นเชื่อมเกินระดับใช้งานจริงที่จัดการกรณีขอบทั้งหมด ได้แก่ โหนดที่เริ่มนับดัชนีจาก 1 เส้นเชื่อมเกินเพียงหนึ่งเส้น และการรับประกันว่าการลบเส้นเชื่อมนั้นจะเหลือต้นไม้ที่ถูกต้อง วิธีนี้ใช้ DSU ที่มีประสิทธิภาพสูงสุด โดยใช้การลดครึ่งเส้นทางและการ union ตามอันดับ

หลังจากส่งคำตอบแล้ว ลองทำคำถามต่อยอด: จะเกิดอะไรขึ้นหากกราฟอาจมีเส้นเชื่อมเกินหลายเส้น คุณจะต้องติดตามเส้นเชื่อมทั้งหมดที่ทำให้เกิดวัฏจักรและส่งคืนเส้นสุดท้ายในรายการข้อมูลเข้า — กลยุทธ์แบบละโมบเดิมยังคงใช้ได้ เพราะ DSU ประมวลผลเส้นเชื่อมตามลำดับ

def find_redundant_connection(edges):
    n = len(edges)
    parent = list(range(n + 1))
    rank = [0] * (n + 1)

    def find(x):
        while parent[x] != x:
            parent[x] = parent[parent[x]]   # path halving
            x = parent[x]
        return x

    def union(x, y):
        px, py = find(x), find(y)
        if px == py:
            return False
        if rank[px] < rank[py]:
            px, py = py, px
        parent[py] = px
        if rank[px] == rank[py]:
            rank[px] += 1
        return True

    for u, v in edges:
        if not union(u, v):
            return [u, v]
    return []  # should never reach here given valid input

test_cases = [
    [[1,2],[1,3],[2,3]],
    [[1,2],[2,3],[3,4],[1,4],[1,5]],
    [[1,2],[1,3],[2,3],[2,4],[3,5]],
]
for tc in test_cases:
    print(find_redundant_connection(tc))

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับแนวคิดโครงสร้างข้อมูล & อัลกอริทึม — การเตรียมตัวสัมภาษณ์การเขียนโปรแกรมจากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า เส้นเชื่อมเกินคือเส้นเชื่อมที่เชื่อมโหนดสองโหนดซึ่งเชื่อมต่อกันอยู่แล้วในกราฟไม่มีทิศทาง DSU ตรวจจับกรณีนี้โดยตรวจสอบ find(u) == find(v) ก่อนทำ union แล้วส่งคืนเส้นเชื่อมนั้น และ กราฟมีทิศทางต้องใช้ DFS แบบสามสีหรืออัลกอริทึมของ Kahn แทน DSU เพื่อตรวจจับวัฏจักร บทถัดไป เราจะใช้ DSU กับปัญหาการผสานบัญชี ซึ่งมีอีเมลเป็นโหนด และอีเมลที่ใช้ร่วมกันระหว่างบัญชีจะทำให้เกิดการ union

คำถามที่พบบ่อย

บทเรียน “การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Coding Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Coding Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร”

ตรวจจับเส้นเชื่อมที่ทำให้เกิดวงจรในกราฟไม่มีทิศทางด้วยการรวมแต่ละเส้นเชื่อม และตรวจสอบว่าโหนดสองตัวเชื่อมโยงกันอยู่แล้วหรือไม่ คุณปฏิบัติ Coding Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Coding Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Coding Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Coding Interview Prep นี้ได้ไหม

ได้ บทเรียน Coding Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. DSU กับการบีบอัดเส้นทาง
  2. การรวมตามอันดับและขอบเขตอินเวอร์สแอกเคอร์มันน์
  3. การเชื่อมโยงเกินจำเป็นและการตรวจจับวงจร
  4. การรวมบัญชีและองค์ประกอบเชื่อมโยง
← กลับไปที่ Coding Interview Prep