कोडिंग साक्षात्कार की तैयारी · पाठ

DFS: जुड़े घटक और Flood Fill

जुड़े घटक गिनने, 2D ग्रिड में number-of-islands हल करने और चित्र संसाधन के लिए flood fill लागू करने हेतु DFS अपनाइए।

पाठ 3, कुल 4 में से13 चरण

DFS: जुड़े घटक और Flood Fill, CoddyKit पर कोडिंग साक्षात्कार की तैयारी का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह कोडिंग साक्षात्कार की तैयारी सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

जुड़े हुए घटक की परिभाषा

अनिर्देशित ग्राफ़ में जुड़ा हुआ घटक वर्टेक्सों का ऐसा अधिकतम समुच्चय है जिसमें समुच्चय के प्रत्येक वर्टेक्स-युग्म के बीच कोई पथ होता है। एक ही ग्राफ़ में कई असंबद्ध घटक हो सकते हैं। जुड़े हुए घटकों को ढूँढ़ना अनेक ग्राफ़ समस्याओं का आधार है: समूह बनाना, विलय, द्वीपों की गिनती और खातों का एकीकरण—इन सभी को इसी मूलभूत प्रक्रिया तक घटाया जा सकता है।

from collections import defaultdict

# Graph with 3 components: {0,1,2}, {3,4}, {5}
graph = defaultdict(list)
for u, v in [(0,1),(0,2),(1,2),(3,4)]:
    graph[u].append(v)
    graph[v].append(u)
# Node 5 is isolated (no edges)
for node in [0,1,2,3,4,5]:
    if node not in graph:
        graph[node] = []

# We need DFS or BFS from each unvisited node
# to discover all components
print('Graph has nodes 0-5 with components: {0,1,2}, {3,4}, {5}')

DFS से जुड़े हुए घटकों की गिनती

सभी नोडों पर जाएँ। प्रत्येक ऐसे नोड के लिए जिसे अभी विज़िट नहीं किया गया है, सभी पहुँच योग्य नोडों को विज़िट किया हुआ चिह्नित करने के लिए DFS शुरू करें। प्रत्येक DFS आरंभ एक नए घटक की खोज के अनुरूप होता है। घटकों की संख्या पाने के लिए DFS आरंभों की गिनती करें। यह O(V + E) एल्गोरिदम सही ढंग से काम करता है, चाहे ग्राफ़ जुड़ा हुआ हो या नहीं।

from collections import defaultdict

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

    visited = set()
    count = 0

    def dfs(node):
        visited.add(node)
        for nb in graph[node]:
            if nb not in visited:
                dfs(nb)

    for node in range(n):
        if node not in visited:
            dfs(node)
            count += 1

    return count

print(count_components(6, [(0,1),(0,2),(1,2),(3,4)]))  # 3
print(count_components(5, [(0,1),(1,2),(3,4)]))          # 2

द्वीपों की संख्या

द्वीपों की संख्या (LeetCode #200) द्वि-आयामी ग्रिड पर जुड़े हुए घटकों की मानक समस्या है। प्रत्येक '1' सेल किसी द्वीप का भाग होता है; आसन्न '1' सेल (ऊपर/नीचे/बाएँ/दाएँ) एक ही द्वीप बनाते हैं। DFS का उपयोग करके अलग-अलग द्वीपों की संख्या गिनें: सभी सेल पर जाएँ और जब कोई ऐसा '1' मिले जिसे अभी विज़िट नहीं किया गया है, तो एक DFS शुरू करें जो सभी जुड़े हुए '1' सेल को चिह्नित करे (क्षेत्र-भराव), फिर गिनती बढ़ाएँ।

def num_islands(grid):
    if not grid:
        return 0
    rows, cols = len(grid), len(grid[0])
    count = 0

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols:
            return
        if grid[r][c] != '1':
            return
        grid[r][c] = '#'  # mark visited in-place
        dfs(r+1,c); dfs(r-1,c)
        dfs(r,c+1); dfs(r,c-1)

    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == '1':
                dfs(r, c)
                count += 1
    return count

grid = [['1','1','0','0','0'],
        ['1','1','0','0','0'],
        ['0','0','1','0','0'],
        ['0','0','0','1','1']]
print(num_islands(grid))  # 3

क्षेत्र-भराव एल्गोरिदम

क्षेत्र-भराव (LeetCode #733) किसी दिए गए आरंभिक रंग वाले सभी जुड़े हुए सेल को नए रंग से बदल देता है—ठीक वैसे ही जैसे चित्र-संपादकों में रंग भरने वाला औज़ार काम करता है। DFS का उपयोग करें: स्रोत पिक्सेल से शुरू करके, मूल रंग से मेल खाने वाले सभी पड़ोसियों का रंग पुनरावर्ती रूप से बदलें। महत्वपूर्ण विशेष स्थिति: यदि आरंभिक सेल का रंग पहले से ही नए रंग के समान है, तो अनंत पुनरावर्तन से बचने के लिए तुरंत लौटें।

def flood_fill(image, sr, sc, new_color):
    original = image[sr][sc]
    if original == new_color:
        return image  # edge case: same color, nothing to do
    rows, cols = len(image), len(image[0])

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols:
            return
        if image[r][c] != original:
            return
        image[r][c] = new_color
        dfs(r+1,c); dfs(r-1,c)
        dfs(r,c+1); dfs(r,c-1)

    dfs(sr, sc)
    return image

image = [[1,1,1],[1,1,0],[1,0,1]]
result = flood_fill(image, 1, 1, 2)
for row in result: print(row)
# [[2,2,2],[2,2,0],[2,0,1]]

द्वीप का अधिकतम क्षेत्रफल

द्वीप का अधिकतम क्षेत्रफल (LeetCode #695) द्वीपों की गिनती को आगे बढ़ाता है: प्रत्येक द्वीप के लिए सबसे बड़े द्वीप का आकार लौटाना होता है। DFS फ़्लड-फ़िल के दौरान चिह्नित किए गए खानों की गिनती करें। DFS वर्तमान द्वीप का आकार लौटाता है और आप सभी द्वीपों में से अधिकतम आकार का अभिलेख रखते हैं। यह जुड़े हुए घटकों के प्रतिरूप का एक सरल विस्तार है।

def max_area_of_island(grid):
    if not grid:
        return 0
    rows, cols = len(grid), len(grid[0])
    max_area = 0

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols:
            return 0
        if grid[r][c] != 1:
            return 0
        grid[r][c] = 0  # mark visited
        return (1 + dfs(r+1,c) + dfs(r-1,c) +
                dfs(r,c+1) + dfs(r,c-1))

    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == 1:
                max_area = max(max_area, dfs(r, c))
    return max_area

grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],
        [0,0,0,0,0,0,0,1,1,1,0,0,0],
        [0,1,1,0,1,0,0,0,0,0,0,0,0],
        [0,1,0,0,1,1,0,0,1,0,1,0,0]]
print(max_area_of_island(grid))  # 6

प्रशांत और अटलांटिक जल प्रवाह

प्रशांत और अटलांटिक जल प्रवाह (LeetCode #417) में पूछा जाता है कि कौन-से खाने प्रशांत महासागर (ऊपरी/बाएँ किनारे) और अटलांटिक महासागर (निचले/दाएँ किनारे) दोनों तक बह सकते हैं। पानी को नीचे की ओर बहते हुए अनुकरण करने के बजाय उल्टा DFS इस्तेमाल करें: पानी महासागरों से ऊपर की ओर बहता है। दो DFS चक्र चलाएँ — एक प्रशांत की सीमाओं से और दूसरा अटलांटिक की सीमाओं से — और पहुँच योग्य खानों को एकत्र करें। दोनों का प्रतिच्छेद ही उत्तर है।

def pacific_atlantic(heights):
    rows, cols = len(heights), len(heights[0])
    pac = set(); atl = set()

    def dfs(r, c, visited, prev_h):
        if (r,c) in visited or r < 0 or r >= rows or c < 0 or c >= cols:
            return
        if heights[r][c] < prev_h:
            return  # water can't flow uphill in reverse
        visited.add((r,c))
        for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
            dfs(r+dr, c+dc, visited, heights[r][c])

    for r in range(rows):
        dfs(r, 0, pac, heights[r][0])           # Pacific left
        dfs(r, cols-1, atl, heights[r][cols-1]) # Atlantic right
    for c in range(cols):
        dfs(0, c, pac, heights[0][c])            # Pacific top
        dfs(rows-1, c, atl, heights[rows-1][c]) # Atlantic bottom

    return sorted(pac & atl)  # intersection

print(pacific_atlantic([[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]))

जुड़े हुए घटकों के लिए पुनरावृत्त DFS

बड़े ग्रिड पर Python की पुनरावृत्ति सीमा से बचने के लिए पुनरावृत्त DFS (स्पष्ट स्टैक के साथ) इस्तेमाल करें। पुनरावृत्त रूप पुनरावर्ती DFS के समतुल्य है, लेकिन कॉल स्टैक के बजाय स्टैक का उपयोग करता है। शुरुआती नोड को स्टैक में डालें, फिर उसे निकालें, देखे गए के रूप में चिह्नित करें और न देखे गए पड़ोसी नोड्स को स्टैक में डालें। इससे लाखों खानों वाले ग्रिड भी सुरक्षित रूप से संभाले जा सकते हैं, जहाँ पुनरावर्ती DFS स्टैक ओवरफ़्लो कर सकता है।

def count_components_iterative(n, edges):
    from collections import defaultdict
    graph = defaultdict(list)
    for u, v in edges:
        graph[u].append(v)
        graph[v].append(u)

    visited = set()
    count = 0

    for start in range(n):
        if start in visited:
            continue
        # Iterative DFS
        stack = [start]
        while stack:
            node = stack.pop()
            if node in visited:
                continue
            visited.add(node)
            for nb in graph[node]:
                if nb not in visited:
                    stack.append(nb)
        count += 1

    return count

print(count_components_iterative(6, [(0,1),(0,2),(1,2),(3,4)]))  # 3

घिरी हुई क्षेत्रें

घिरी हुई क्षेत्रें (LeetCode #130) उन सभी 'O' क्षेत्रों को ढूँढ़ता है जो पूरी तरह 'X' सीमाओं से घिरी हैं। यदि उसके किसी 'O' खाने का बोर्ड के किनारे से संपर्क हो, तो वह क्षेत्र NOT पकड़ी जाती है। युक्ति यह है कि घिरी हुई क्षेत्रों को सीधे ढूँढ़ने के बजाय सभी सीमा वाले 'O' खानों से DFS करें और जहाँ तक पहुँचा जा सके, वहाँ तक सब कुछ सुरक्षित के रूप में चिह्नित करें। फिर पलटें: बाकी सभी 'O' खाने घिरे हुए हैं और 'X' बन जाते हैं, जबकि सुरक्षित खाने वापस 'O' कर दिए जाते हैं।

def solve(board):
    if not board:
        return
    rows, cols = len(board), len(board[0])

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols:
            return
        if board[r][c] != 'O':
            return
        board[r][c] = 'S'  # safe: connected to border
        dfs(r+1,c); dfs(r-1,c)
        dfs(r,c+1); dfs(r,c-1)

    # Mark border-connected O's as safe
    for r in range(rows):
        dfs(r, 0); dfs(r, cols-1)
    for c in range(cols):
        dfs(0, c); dfs(rows-1, c)

    # Flip: surrounded O -> X, safe S -> O
    for r in range(rows):
        for c in range(cols):
            if board[r][c] == 'O': board[r][c] = 'X'
            elif board[r][c] == 'S': board[r][c] = 'O'

board = [['X','X','X','X'],['X','O','O','X'],
         ['X','X','O','X'],['X','O','X','X']]
solve(board)
print([board[1][1], board[3][1]])  # X, O

उप-द्वीपों की गिनती

उप-द्वीपों की गिनती (LeetCode #1905) ग्रिड2 में उन द्वीपों को ढूँढ़ता है जो पूरी तरह ग्रिड1 के किसी द्वीप के भीतर स्थित हैं। ग्रिड2 के प्रत्येक '1' खाने से DFS करें: कोई द्वीप तभी उप-द्वीप है जब उसके द्वारा देखे गए प्रत्येक खाने का मान ग्रिड1 में भी '1' हो। युक्ति यह है कि द्वीप के ALL खानों पर जाएँ (ताकि वे अन्वेषित के रूप में चिह्नित हो जाएँ), लेकिन यह भी दर्ज करते रहें कि क्या वे ALL ग्रिड1 में भी '1' थे। ग्रिड1 में पहला '0' मिलते ही तुरंत रुकें नहीं — ऐसा करने पर उसी द्वीप के बाकी खानों को चिह्नित करना छूट जाएगा।

def count_sub_islands(grid1, grid2):
    rows, cols = len(grid2), len(grid2[0])

    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols:
            return True
        if grid2[r][c] != 1:
            return True
        grid2[r][c] = 0  # mark visited
        is_sub = grid1[r][c] == 1  # this cell must be in grid1
        is_sub = dfs(r+1,c) and is_sub  # note: AND not short-circuit OR
        is_sub = dfs(r-1,c) and is_sub
        is_sub = dfs(r,c+1) and is_sub
        is_sub = dfs(r,c-1) and is_sub
        return is_sub

    count = 0
    for r in range(rows):
        for c in range(cols):
            if grid2[r][c] == 1 and dfs(r, c):
                count += 1
    return count

print(count_sub_islands([[1,1,1],[1,0,1],[1,1,1]],
                         [[1,1,1],[1,0,1],[1,1,1]]))  # 1

जुड़े हुए घटकों के लिए DFS बनाम BFS

DFS और BFS दोनों समान O(V + E) समय और O(V) स्थान जटिलता के साथ सभी जुड़े हुए घटकों को सही ढंग से ढूँढ़ते हैं। जुड़े हुए घटकों की समस्याओं के लिए पुनरावर्ती रूप में DFS लागू करना सरल होता है, जबकि जब आपको सबसे छोटे पथ की जानकारी भी चाहिए हो, तब BFS को प्राथमिकता दी जाती है। ग्रिड की समस्याओं में DFS कैश के लिए अधिक अनुकूल होता है, क्योंकि पीछे लौटने से पहले यह एक दिशा में गहराई तक जाता है और पास-पास के स्मृति स्थानों को क्रमिक रूप से पढ़ता है।

# DFS advantages for connected components:
# - Simpler recursive implementation
# - Lower constant factor for small graphs
# - Can restore grid state during backtracking (if needed)

# BFS advantages:
# - Finds shortest path while traversing
# - Better for wide, shallow graphs (avoids deep recursion)
# - Multi-source initialisation is natural

# Same asymptotic complexity: O(V + E) time, O(V) space
# Grid (m rows, n cols): O(mn) time and space
print('DFS and BFS: same O(V+E) complexity for component counting')

प्रतिबंधों वाले द्वीप: आकृतियाँ और परिमाप

द्वीप का परिमाप (LeetCode #463) ग्रिड में मौजूद एकमात्र द्वीप का कुल परिमाप गिनता है। प्रत्येक भूमि खाने ('1') के लिए परिमाप में 4 जोड़ें, फिर प्रत्येक सटे हुए भूमि खाने (साझा किनारे) के लिए 2 घटाएँ। इस O(mn) सूत्र-आधारित तरीके में DFS की आवश्यकता नहीं होती — लेकिन यह समझना कि यह सीमा-किनारों की गिनती करने वाले DFS के समतुल्य है, ग्रिड की समस्याओं और ग्राफ़-आधारित तर्क के बीच संबंध को मजबूत करता है।

def island_perimeter(grid):
    rows, cols = len(grid), len(grid[0])
    perimeter = 0
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == 1:
                perimeter += 4  # start with 4 sides
                # Subtract shared edges with adjacent land cells
                if r > 0 and grid[r-1][c] == 1:
                    perimeter -= 2  # shared top edge
                if c > 0 and grid[r][c-1] == 1:
                    perimeter -= 2  # shared left edge
    return perimeter

grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
print(island_perimeter(grid))  # 16

त्वरित जाँच

इस पाठ में सिखाई गई डेटा संरचनाएँ और एल्गोरिदम — कोडिंग साक्षात्कार की तैयारी — से संबंधित अवधारणाओं की अपनी समझ जाँचें।

पाठ का पुनरावलोकन

इस पाठ में आपने सीखा: देखे गए खानों का अभिलेख रखते हुए DFS द्वारा जुड़े हुए घटक, द्वीपों की संख्या और फ़्लड फ़िल को मानक 2D ग्रिड अनुप्रयोगों के रूप में, और सीमाओं से उल्टा DFS (घिरी हुई क्षेत्रें) तथा प्रतिबंधों का अभिलेख रखने वाला बहु-DFS (उप-द्वीप) जैसे उन्नत प्रतिरूप। अब हम निर्देशित और अनिर्देशित ग्राफ़ में चक्रों की पहचान पर काम करेंगे।

शुरुआत निःशुल्क

एआई शिक्षक के साथ कोडिंग साक्षात्कार की तैयारी सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
90
पाठ
360

अक्सर पूछे जाने वाले प्रश्न

क्या “DFS: जुड़े घटक और Flood Fill” पाठ निःशुल्क है?

हाँ—“DFS: जुड़े घटक और Flood Fill” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। कोडिंग साक्षात्कार की तैयारी पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“DFS: जुड़े घटक और Flood Fill” में मैं क्या सीखूँगा?

जुड़े घटक गिनने, 2D ग्रिड में number-of-islands हल करने और चित्र संसाधन के लिए flood fill लागू करने हेतु DFS अपनाइए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ कोडिंग साक्षात्कार की तैयारी का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या कोडिंग साक्षात्कार की तैयारी शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर कोडिंग साक्षात्कार की तैयारी शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।

“DFS: जुड़े घटक और Flood Fill” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस कोडिंग साक्षात्कार की तैयारी पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर कोडिंग साक्षात्कार की तैयारी पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. ग्राफ निरूपण और भ्रमण की तैयारी
  2. BFS: सबसे छोटा पथ और स्तर-भ्रमण
  3. DFS: जुड़े घटक और Flood Fill
  4. निर्देशित और अनिर्देशित ग्राफ में चक्र पहचान
← कोडिंग साक्षात्कार की तैयारी पर वापस जाएँ