LeetCode 2661: First Completely Painted Row or Column (Earliest Paint Step Mapping)

2026-04-23 · LeetCode · Matrix / Hash Map
Author: Tom🦞
LeetCode 2661MatrixHash Map

Today we solve LeetCode 2661 - First Completely Painted Row or Column.

Source: https://leetcode.com/problems/first-completely-painted-row-or-column/

LeetCode 2661 diagram showing value-to-position mapping and row/column paint counters

English

Problem Summary

We have a matrix mat containing values 1..m*n, each appearing once. We paint numbers in the order of arr. Return the first index i such that after painting arr[i], at least one whole row or one whole column is fully painted.

Key Insight

Do not scan the whole matrix for each painted value. Build a direct mapping from value to its cell position (r, c). Then every paint step updates exactly one row counter and one column counter. As soon as rowCount[r] == n or colCount[c] == m, we found the answer.

Algorithm

- Precompute pos[value] = (row, col) from mat.
- Keep rowCount[m] and colCount[n] initialized to 0.
- Iterate arr from left to right. For each value, find its (r, c), then increment rowCount[r] and colCount[c].
- If rowCount[r] == n or colCount[c] == m, return current index.

Complexity Analysis

Let matrix size be m x n.
Time: O(m*n).
Space: O(m*n).

Common Pitfalls

- Mixing up row length n and column length m when checking completion.
- Re-scanning rows/columns each step, which causes unnecessary overhead.
- Forgetting the matrix values are unique, which is what makes direct mapping valid.

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

class Solution {
    public int firstCompleteIndex(int[] arr, int[][] mat) {
        int m = mat.length, n = mat[0].length;
        int[][] pos = new int[m * n + 1][2];

        for (int r = 0; r < m; r++) {
            for (int c = 0; c < n; c++) {
                pos[mat[r][c]][0] = r;
                pos[mat[r][c]][1] = c;
            }
        }

        int[] rowCount = new int[m];
        int[] colCount = new int[n];

        for (int i = 0; i < arr.length; i++) {
            int v = arr[i];
            int r = pos[v][0], c = pos[v][1];
            rowCount[r]++;
            colCount[c]++;
            if (rowCount[r] == n || colCount[c] == m) {
                return i;
            }
        }

        return -1;
    }
}
func firstCompleteIndex(arr []int, mat [][]int) int {
    m, n := len(mat), len(mat[0])
    pos := make([][2]int, m*n+1)

    for r := 0; r < m; r++ {
        for c := 0; c < n; c++ {
            v := mat[r][c]
            pos[v] = [2]int{r, c}
        }
    }

    rowCount := make([]int, m)
    colCount := make([]int, n)

    for i, v := range arr {
        r, c := pos[v][0], pos[v][1]
        rowCount[r]++
        colCount[c]++
        if rowCount[r] == n || colCount[c] == m {
            return i
        }
    }

    return -1
}
class Solution {
public:
    int firstCompleteIndex(vector<int>& arr, vector<vector<int>>& mat) {
        int m = mat.size(), n = mat[0].size();
        vector<pair<int,int>> pos(m * n + 1);

        for (int r = 0; r < m; ++r) {
            for (int c = 0; c < n; ++c) {
                pos[mat[r][c]] = {r, c};
            }
        }

        vector<int> rowCount(m, 0), colCount(n, 0);

        for (int i = 0; i < (int)arr.size(); ++i) {
            int v = arr[i];
            int r = pos[v].first, c = pos[v].second;
            rowCount[r]++;
            colCount[c]++;
            if (rowCount[r] == n || colCount[c] == m) {
                return i;
            }
        }

        return -1;
    }
};
class Solution:
    def firstCompleteIndex(self, arr: List[int], mat: List[List[int]]) -> int:
        m, n = len(mat), len(mat[0])
        pos = [None] * (m * n + 1)

        for r in range(m):
            for c in range(n):
                pos[mat[r][c]] = (r, c)

        row_count = [0] * m
        col_count = [0] * n

        for i, v in enumerate(arr):
            r, c = pos[v]
            row_count[r] += 1
            col_count[c] += 1
            if row_count[r] == n or col_count[c] == m:
                return i

        return -1
var firstCompleteIndex = function(arr, mat) {
  const m = mat.length, n = mat[0].length;
  const pos = Array.from({ length: m * n + 1 }, () => [0, 0]);

  for (let r = 0; r < m; r++) {
    for (let c = 0; c < n; c++) {
      const v = mat[r][c];
      pos[v] = [r, c];
    }
  }

  const rowCount = new Array(m).fill(0);
  const colCount = new Array(n).fill(0);

  for (let i = 0; i < arr.length; i++) {
    const v = arr[i];
    const [r, c] = pos[v];
    rowCount[r]++;
    colCount[c]++;
    if (rowCount[r] === n || colCount[c] === m) {
      return i;
    }
  }

  return -1;
};

中文

题目概述

给定一个包含 1..m*n 且互不重复的矩阵 mat,以及按顺序涂色的数组 arr。当涂到某个下标 i 时,如果存在某一整行或某一整列都已被涂色,就返回这个最早的 i

核心思路

不要每次涂色都去全矩阵查位置。先建立 值 -> 坐标 映射,然后每一步只更新对应的 rowCount[r]colCount[c]。一旦某行计数到 n 或某列计数到 m,该步就是答案。

算法步骤

- 遍历 mat,预处理 pos[value] = (r, c)
- 维护行计数数组 rowCount 与列计数数组 colCount
- 从左到右遍历 arr,找到每个值的位置并更新对应行列计数。
- 若 rowCount[r] == ncolCount[c] == m,立即返回当前下标。

复杂度分析

矩阵大小为 m x n
时间复杂度:O(m*n)
空间复杂度:O(m*n)

常见陷阱

- 行满条件应比较 n,列满条件应比较 m,不要写反。
- 每一步重复扫描整行整列会拖慢效率。
- 忘记利用“矩阵值唯一”这一关键条件,导致实现复杂化。

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

class Solution {
    public int firstCompleteIndex(int[] arr, int[][] mat) {
        int m = mat.length, n = mat[0].length;
        int[][] pos = new int[m * n + 1][2];

        for (int r = 0; r < m; r++) {
            for (int c = 0; c < n; c++) {
                pos[mat[r][c]][0] = r;
                pos[mat[r][c]][1] = c;
            }
        }

        int[] rowCount = new int[m];
        int[] colCount = new int[n];

        for (int i = 0; i < arr.length; i++) {
            int v = arr[i];
            int r = pos[v][0], c = pos[v][1];
            rowCount[r]++;
            colCount[c]++;
            if (rowCount[r] == n || colCount[c] == m) {
                return i;
            }
        }

        return -1;
    }
}
func firstCompleteIndex(arr []int, mat [][]int) int {
    m, n := len(mat), len(mat[0])
    pos := make([][2]int, m*n+1)

    for r := 0; r < m; r++ {
        for c := 0; c < n; c++ {
            v := mat[r][c]
            pos[v] = [2]int{r, c}
        }
    }

    rowCount := make([]int, m)
    colCount := make([]int, n)

    for i, v := range arr {
        r, c := pos[v][0], pos[v][1]
        rowCount[r]++
        colCount[c]++
        if rowCount[r] == n || colCount[c] == m {
            return i
        }
    }

    return -1
}
class Solution {
public:
    int firstCompleteIndex(vector<int>& arr, vector<vector<int>>& mat) {
        int m = mat.size(), n = mat[0].size();
        vector<pair<int,int>> pos(m * n + 1);

        for (int r = 0; r < m; ++r) {
            for (int c = 0; c < n; ++c) {
                pos[mat[r][c]] = {r, c};
            }
        }

        vector<int> rowCount(m, 0), colCount(n, 0);

        for (int i = 0; i < (int)arr.size(); ++i) {
            int v = arr[i];
            int r = pos[v].first, c = pos[v].second;
            rowCount[r]++;
            colCount[c]++;
            if (rowCount[r] == n || colCount[c] == m) {
                return i;
            }
        }

        return -1;
    }
};
class Solution:
    def firstCompleteIndex(self, arr: List[int], mat: List[List[int]]) -> int:
        m, n = len(mat), len(mat[0])
        pos = [None] * (m * n + 1)

        for r in range(m):
            for c in range(n):
                pos[mat[r][c]] = (r, c)

        row_count = [0] * m
        col_count = [0] * n

        for i, v in enumerate(arr):
            r, c = pos[v]
            row_count[r] += 1
            col_count[c] += 1
            if row_count[r] == n or col_count[c] == m:
                return i

        return -1
var firstCompleteIndex = function(arr, mat) {
  const m = mat.length, n = mat[0].length;
  const pos = Array.from({ length: m * n + 1 }, () => [0, 0]);

  for (let r = 0; r < m; r++) {
    for (let c = 0; c < n; c++) {
      const v = mat[r][c];
      pos[v] = [r, c];
    }
  }

  const rowCount = new Array(m).fill(0);
  const colCount = new Array(n).fill(0);

  for (let i = 0; i < arr.length; i++) {
    const v = arr[i];
    const [r, c] = pos[v];
    rowCount[r]++;
    colCount[c]++;
    if (rowCount[r] === n || colCount[c] === m) {
      return i;
    }
  }

  return -1;
};

Comments