Close Menu
    Code and Debug
    • Home
    • Our Courses
    • Blog
    • About Us
    • Contact Us
    Facebook X (Twitter) Instagram YouTube WhatsApp
    • Home
    • Our Courses
    • Blog
    • About Us
    • Contact Us
    Facebook Instagram YouTube LinkedIn WhatsApp
    Code and Debug – BlogCode and Debug – Blog
    Code and Debug – BlogCode and Debug – Blog
    Home»Data Structures & Algorithms»Surrounded Regions | Leetcode 130 | Explained using DFS
    Data Structures & Algorithms

    Surrounded Regions | Leetcode 130 | Explained using DFS

    codeanddebugBy codeanddebug27 May 2025Updated:27 May 2025No Comments5 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Telegram Email
    Featured Image of a question of Surrounded Regions on leetcode
    Share
    Facebook Twitter LinkedIn Pinterest Email

    Learn how to solve the Surrounded Regions problem by marking all ‘O’s connected to the border via DFS, then flipping the rest. Two in-place DFS solutions are explained step by step with comments.

    Content
     [show]
    • What the Problem Asks
    • The Easy Idea
    • Solution 1: One Loop Over Every Border Cell
      • Step-by-Step Explanation
    • Solution 2: Four Separate Border Loops
      • Step-by-Step Explanation
    • Why This Works
    • Time & Space Complexity
    • Conclusion

    What the Problem Asks

    LeetCode 130: Surrounded Regions
    You have a 2D board of letters 'X' and 'O'. You want to flip every 'O' that is completely surrounded by 'X' on all four sides into an 'X'. An 'O' is not surrounded if it’s connected (directly or indirectly) to any 'O' on the border of the board.

    In other words:

    • Any group of 'O's entirely inside gets turned into 'X'.
    • Any group of 'O's that touches the edge of the board stays 'O'.

    The Easy Idea

    1. Find all ‘O’s on the border (top row, bottom row, left column, right column).
    2. Mark every ‘O’ that connects to those border ‘O’s (using DFS). These are the ones we don’t flip.
    3. Flip all the other ‘O’s—those that never got marked—into ‘X’.

    That way, you only flip the truly enclosed regions.

    Solution 1: One Loop Over Every Border Cell

    class Solution:
        def dfs(self, r, c, visited, rows, cols, board):
            # If out of bounds, stop
            if r < 0 or r >= rows or c < 0 or c >= cols:
                return
            # If it's an 'X', stop
            if board[r][c] == "X":
                return
            # If already marked as border-connected, stop
            if visited[r][c] == 1:
                return
            # Mark this 'O' as connected to the border
            visited[r][c] = 1
            # Recurse up, left, right, down
            self.dfs(r - 1, c, visited, rows, cols, board)
            self.dfs(r, c - 1, visited, rows, cols, board)
            self.dfs(r, c + 1, visited, rows, cols, board)
            self.dfs(r + 1, c, visited, rows, cols, board)
    
        def solve(self, board: List[List[str]]) -> None:
            """
            Do not return anything, modify board in-place instead.
            """
            rows = len(board)
            cols = len(board[0])
            # 0 = unvisited, 1 = connected-to-border
            visited = [[0 for _ in range(cols)] for _ in range(rows)]
    
            # 1. Check every cell on the border
            for r in range(rows):
                for c in range(cols):
                    # Is this cell on the outer border?
                    if r == 0 or c == 0 or r == rows - 1 or c == cols - 1:
                        # If it's an 'O' and not yet visited, run DFS
                        if board[r][c] == "O":
                            if visited[r][c] == 0:
                                self.dfs(r, c, visited, rows, cols, board)
    
            # 2. Flip all 'O's that were never marked
            for r in range(rows):
                for c in range(cols):
                    if board[r][c] == "O" and visited[r][c] == 0:
                        board[r][c] = "X"
    

    Step-by-Step Explanation

    1. Build visited array same size as board, initialized to 0.
    2. Border scan:
      • Loop over every cell (r,c).
      • If it’s on the very first row, last row, first column, or last column and is an 'O', call dfs.
    3. dfs(r,c) marks the current 'O' visited, then does the same for any adjacent 'O'.
    4. Final pass:
      • Any 'O' still unvisited must be fully surrounded—flip it to 'X'.

    Solution 2: Four Separate Border Loops

    class Solution:
        def dfs(self, r, c, visited, rows, cols, board):
            if r < 0 or r >= rows or c < 0 or c >= cols:
                return
            if board[r][c] == "X":
                return
            if visited[r][c] == 1:
                return
            visited[r][c] = 1
            self.dfs(r - 1, c, visited, rows, cols, board)
            self.dfs(r, c - 1, visited, rows, cols, board)
            self.dfs(r, c + 1, visited, rows, cols, board)
            self.dfs(r + 1, c, visited, rows, cols, board)
    
        def solve(self, board: List[List[str]]) -> None:
            """
            Do not return anything, modify board in-place instead.
            """
            rows = len(board)
            cols = len(board[0])
            visited = [[0 for _ in range(cols)] for _ in range(rows)]
    
            # Upper Row
            r, c = 0, 0
            for c in range(cols):
                if board[r][c] == "O":
                    if visited[r][c] == 0:
                        self.dfs(r, c, visited, rows, cols, board)
    
            # Last Row
            r, c = rows - 1, 0
            for c in range(cols):
                if board[r][c] == "O":
                    if visited[r][c] == 0:
                        self.dfs(r, c, visited, rows, cols, board)
    
            # First Column
            r, c = 0, 0
            for r in range(rows):
                if board[r][c] == "O":
                    if visited[r][c] == 0:
                        self.dfs(r, c, visited, rows, cols, board)
    
            # Last Column
            r, c = 0, cols - 1
            for r in range(rows):
                if board[r][c] == "O":
                    if visited[r][c] == 0:
                        self.dfs(r, c, visited, rows, cols, board)
    
            # Flip the interior 'O's that remain unvisited
            for r in range(rows):
                for c in range(cols):
                    if board[r][c] == "O" and visited[r][c] == 0:
                        board[r][c] = "X"

    Step-by-Step Explanation

    1. Initialize visited to all zeros.
    2. Four border sweeps:
      • Go across the top row, bottom row, left column, then right column.
      • For each border cell that’s an 'O' and unvisited, call dfs.
    3. dfs marks all 'O's connected to that border cell.
    4. Final sweep:
      • Any 'O' still unvisited lies in a fully surrounded region—flip it to 'X'.

    Why This Works

    • Any 'O' that can’t reach the border (via up/down/left/right moves) is surrounded.
    • DFS from border cells marks exactly those 'O's that should stay.
    • All others get flipped in a single final pass.

    Time & Space Complexity

    1. Time Complexity: O(m·n.4)
      • Each DFS visits each cell at most once with looking into every direction.
    2. Space Complexity: O(m·n)
      • The visited matrix and call stack (in worst case) can grow to the whole board.

    Conclusion

    By first marking all 'O' cells connected to the border (the only ones that shouldn’t be flipped), we can safely flip every other 'O' to 'X'. Both solutions run in linear time and update the board in-place. Choose whichever border-traversal style you find more readable!

    Join our Advance DSA COURSE

    For any changes to the article, kindly email at code@codeanddebug.in or contact us at +91-9712928220.

    Graph
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous Article01 Matrix | Leetcode 542 | Explained using BFS
    Next Article 4 Stunning Portfolio Website Templates for Students – Free & Customizable
    codeanddebug
    • Website

    Related Posts

    Data Structures & Algorithms

    Bubble Sort Algorithm in Python | Explained in Depth

    29 May 2025
    Data Structures & Algorithms

    Python Program to Find Factorial of Number Using Recursion

    29 May 2025
    Data Structures & Algorithms

    Python Program to Print from 1 to N Without Loops

    29 May 2025
    Add A Comment
    Leave A Reply Cancel Reply

    Categories
    • Data Structures & Algorithms (30)
      • Beginner (16)
      • Expert (5)
      • Intermediate (9)
    • Uncategorised (1)
    Recent Posts

    Bubble Sort Algorithm in Python | Explained in Depth

    29 May 2025

    Python Program to Find Factorial of Number Using Recursion

    29 May 2025

    Python Program to Print from 1 to N Without Loops

    29 May 2025

    Python Program to Print Divisors/Factors of an Integer

    28 May 2025

    Python Program to Check Armstrong Number | Explained

    28 May 2025
    Facebook Instagram YouTube LinkedIn WhatsApp
    © 2025 Code and Debug. All rights reserved.

    Type above and press Enter to search. Press Esc to cancel.