LeetCode 1034: Coloring A Border (DFS Component Border Detection)

2026-04-27 · LeetCode · Graph / DFS
Author: Tom🦞
LeetCode 1034GraphDFS

Today we solve LeetCode 1034 - Coloring A Border.

Source: https://leetcode.com/problems/coloring-a-border/

LeetCode 1034 DFS border coloring diagram

English

Problem Summary

We start from (row, col), collect its connected component of same color, and repaint only the border cells of that component with the new color.

Key Insight

A cell is a border if it is on the grid edge, or it has at least one 4-direction neighbor with a different color. DFS can traverse the whole component and decide border status per cell.

Algorithm

- Save the original color of the component.
- DFS only through cells with that original color.
- For each visited cell, mark border if it touches outside or different-color neighbor.
- Repaint only recorded border cells.

Complexity Analysis

Let component size be k.
Time: O(k).
Space: O(k) for visited and recursion stack.

Common Pitfalls

- Recoloring during DFS and breaking neighbor checks.
- Traversing into different-color cells.
- Forgetting that edge cells are always border.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    private int m, n;
    private int origin;
    private boolean[][] vis;
    private final int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};

    public int[][] colorBorder(int[][] grid, int row, int col, int color) {
        m = grid.length;
        n = grid[0].length;
        origin = grid[row][col];
        vis = new boolean[m][n];
        java.util.List<int[]> border = new java.util.ArrayList<>();
        dfs(grid, row, col, border);
        for (int[] cell : border) {
            grid[cell[0]][cell[1]] = color;
        }
        return grid;
    }

    private void dfs(int[][] grid, int r, int c, java.util.List<int[]> border) {
        vis[r][c] = true;
        boolean isBorder = (r == 0 || r == m - 1 || c == 0 || c == n - 1);

        for (int[] d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
                isBorder = true;
                continue;
            }
            if (grid[nr][nc] != origin) {
                isBorder = true;
                continue;
            }
            if (!vis[nr][nc]) dfs(grid, nr, nc, border);
        }

        if (isBorder) border.add(new int[]{r, c});
    }
}
func colorBorder(grid [][]int, row int, col int, color int) [][]int {
    m, n := len(grid), len(grid[0])
    origin := grid[row][col]
    vis := make([][]bool, m)
    for i := range vis {
        vis[i] = make([]bool, n)
    }

    dirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
    border := make([][2]int, 0)

    var dfs func(int, int)
    dfs = func(r, c int) {
        vis[r][c] = true
        isBorder := r == 0 || r == m-1 || c == 0 || c == n-1

        for _, d := range dirs {
            nr, nc := r+d[0], c+d[1]
            if nr < 0 || nr >= m || nc < 0 || nc >= n {
                isBorder = true
                continue
            }
            if grid[nr][nc] != origin {
                isBorder = true
                continue
            }
            if !vis[nr][nc] {
                dfs(nr, nc)
            }
        }

        if isBorder {
            border = append(border, [2]int{r, c})
        }
    }

    dfs(row, col)
    for _, p := range border {
        grid[p[0]][p[1]] = color
    }
    return grid
}
class Solution {
public:
    int m, n, origin;
    vector<vector<bool>> vis;
    vector<pair<int,int>> border;
    int dr[4] = {1, -1, 0, 0};
    int dc[4] = {0, 0, 1, -1};

    vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
        m = grid.size();
        n = grid[0].size();
        origin = grid[row][col];
        vis.assign(m, vector<bool>(n, false));
        dfs(grid, row, col);
        for (auto &p : border) grid[p.first][p.second] = color;
        return grid;
    }

    void dfs(vector<vector<int>>& grid, int r, int c) {
        vis[r][c] = true;
        bool isBorder = (r == 0 || r == m - 1 || c == 0 || c == n - 1);

        for (int k = 0; k < 4; ++k) {
            int nr = r + dr[k], nc = c + dc[k];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
                isBorder = true;
                continue;
            }
            if (grid[nr][nc] != origin) {
                isBorder = true;
                continue;
            }
            if (!vis[nr][nc]) dfs(grid, nr, nc);
        }

        if (isBorder) border.push_back({r, c});
    }
};
class Solution:
    def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
        m, n = len(grid), len(grid[0])
        origin = grid[row][col]
        vis = [[False] * n for _ in range(m)]
        border = []

        def dfs(r: int, c: int) -> None:
            vis[r][c] = True
            is_border = r == 0 or r == m - 1 or c == 0 or c == n - 1

            for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                nr, nc = r + dr, c + dc
                if nr < 0 or nr >= m or nc < 0 or nc >= n:
                    is_border = True
                    continue
                if grid[nr][nc] != origin:
                    is_border = True
                    continue
                if not vis[nr][nc]:
                    dfs(nr, nc)

            if is_border:
                border.append((r, c))

        dfs(row, col)
        for r, c in border:
            grid[r][c] = color
        return grid
/**
 * @param {number[][]} grid
 * @param {number} row
 * @param {number} col
 * @param {number} color
 * @return {number[][]}
 */
var colorBorder = function(grid, row, col, color) {
  const m = grid.length, n = grid[0].length;
  const origin = grid[row][col];
  const vis = Array.from({ length: m }, () => Array(n).fill(false));
  const border = [];
  const dirs = [[1,0],[-1,0],[0,1],[0,-1]];

  const dfs = (r, c) => {
    vis[r][c] = true;
    let isBorder = r === 0 || r === m - 1 || c === 0 || c === n - 1;

    for (const [dr, dc] of dirs) {
      const nr = r + dr, nc = c + dc;
      if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
        isBorder = true;
        continue;
      }
      if (grid[nr][nc] !== origin) {
        isBorder = true;
        continue;
      }
      if (!vis[nr][nc]) dfs(nr, nc);
    }

    if (isBorder) border.push([r, c]);
  };

  dfs(row, col);
  for (const [r, c] of border) {
    grid[r][c] = color;
  }
  return grid;
};

中文

题目概述

(row, col) 出发,找到与起点同色的连通块,只把这个连通块的边界格子涂成新颜色。

核心思路

边界格子的判定有两种情况:在矩阵外圈,或者四联通邻居里存在不同颜色。用 DFS 只遍历同色连通块,同时判断每个格子是否边界。

算法步骤

- 记录起点原色 origin
- DFS 仅进入颜色等于 origin 的格子。
- 若当前格子触边或邻居异色,记为边界。
- DFS 结束后统一给边界格子上色。

复杂度分析

设连通块大小为 k
时间复杂度:O(k)
空间复杂度:O(k)(访问标记与递归栈)。

常见陷阱

- DFS 过程中直接改色,导致后续判定混乱。
- 误走到非原色格子。
- 忘记最外圈格子天然是边界。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    private int m, n;
    private int origin;
    private boolean[][] vis;
    private final int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};

    public int[][] colorBorder(int[][] grid, int row, int col, int color) {
        m = grid.length;
        n = grid[0].length;
        origin = grid[row][col];
        vis = new boolean[m][n];
        java.util.List<int[]> border = new java.util.ArrayList<>();
        dfs(grid, row, col, border);
        for (int[] cell : border) {
            grid[cell[0]][cell[1]] = color;
        }
        return grid;
    }

    private void dfs(int[][] grid, int r, int c, java.util.List<int[]> border) {
        vis[r][c] = true;
        boolean isBorder = (r == 0 || r == m - 1 || c == 0 || c == n - 1);

        for (int[] d : dirs) {
            int nr = r + d[0], nc = c + d[1];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
                isBorder = true;
                continue;
            }
            if (grid[nr][nc] != origin) {
                isBorder = true;
                continue;
            }
            if (!vis[nr][nc]) dfs(grid, nr, nc, border);
        }

        if (isBorder) border.add(new int[]{r, c});
    }
}
func colorBorder(grid [][]int, row int, col int, color int) [][]int {
    m, n := len(grid), len(grid[0])
    origin := grid[row][col]
    vis := make([][]bool, m)
    for i := range vis {
        vis[i] = make([]bool, n)
    }

    dirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
    border := make([][2]int, 0)

    var dfs func(int, int)
    dfs = func(r, c int) {
        vis[r][c] = true
        isBorder := r == 0 || r == m-1 || c == 0 || c == n-1

        for _, d := range dirs {
            nr, nc := r+d[0], c+d[1]
            if nr < 0 || nr >= m || nc < 0 || nc >= n {
                isBorder = true
                continue
            }
            if grid[nr][nc] != origin {
                isBorder = true
                continue
            }
            if !vis[nr][nc] {
                dfs(nr, nc)
            }
        }

        if isBorder {
            border = append(border, [2]int{r, c})
        }
    }

    dfs(row, col)
    for _, p := range border {
        grid[p[0]][p[1]] = color
    }
    return grid
}
class Solution {
public:
    int m, n, origin;
    vector<vector<bool>> vis;
    vector<pair<int,int>> border;
    int dr[4] = {1, -1, 0, 0};
    int dc[4] = {0, 0, 1, -1};

    vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
        m = grid.size();
        n = grid[0].size();
        origin = grid[row][col];
        vis.assign(m, vector<bool>(n, false));
        dfs(grid, row, col);
        for (auto &p : border) grid[p.first][p.second] = color;
        return grid;
    }

    void dfs(vector<vector<int>>& grid, int r, int c) {
        vis[r][c] = true;
        bool isBorder = (r == 0 || r == m - 1 || c == 0 || c == n - 1);

        for (int k = 0; k < 4; ++k) {
            int nr = r + dr[k], nc = c + dc[k];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
                isBorder = true;
                continue;
            }
            if (grid[nr][nc] != origin) {
                isBorder = true;
                continue;
            }
            if (!vis[nr][nc]) dfs(grid, nr, nc);
        }

        if (isBorder) border.push_back({r, c});
    }
};
class Solution:
    def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
        m, n = len(grid), len(grid[0])
        origin = grid[row][col]
        vis = [[False] * n for _ in range(m)]
        border = []

        def dfs(r: int, c: int) -> None:
            vis[r][c] = True
            is_border = r == 0 or r == m - 1 or c == 0 or c == n - 1

            for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                nr, nc = r + dr, c + dc
                if nr < 0 or nr >= m or nc < 0 or nc >= n:
                    is_border = True
                    continue
                if grid[nr][nc] != origin:
                    is_border = True
                    continue
                if not vis[nr][nc]:
                    dfs(nr, nc)

            if is_border:
                border.append((r, c))

        dfs(row, col)
        for r, c in border:
            grid[r][c] = color
        return grid
/**
 * @param {number[][]} grid
 * @param {number} row
 * @param {number} col
 * @param {number} color
 * @return {number[][]}
 */
var colorBorder = function(grid, row, col, color) {
  const m = grid.length, n = grid[0].length;
  const origin = grid[row][col];
  const vis = Array.from({ length: m }, () => Array(n).fill(false));
  const border = [];
  const dirs = [[1,0],[-1,0],[0,1],[0,-1]];

  const dfs = (r, c) => {
    vis[r][c] = true;
    let isBorder = r === 0 || r === m - 1 || c === 0 || c === n - 1;

    for (const [dr, dc] of dirs) {
      const nr = r + dr, nc = c + dc;
      if (nr < 0 || nr >= m || nc < 0 || nc >= n) {
        isBorder = true;
        continue;
      }
      if (grid[nr][nc] !== origin) {
        isBorder = true;
        continue;
      }
      if (!vis[nr][nc]) dfs(nr, nc);
    }

    if (isBorder) border.push([r, c]);
  };

  dfs(row, col);
  for (const [r, c] of border) {
    grid[r][c] = color;
  }
  return grid;
};

Comments