Skip to content

3242. Design Neighbor Sum Service

On LeetCode ->

Problem

Given an \(n \times n\) grid containing each value from \(0\) to \(n^2-1\) exactly once, support queries for the sum of a value's orthogonal or diagonal neighbors.

grid = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
adjacentSum(4) -> 16  # 1 + 3 + 5 + 7
diagonalSum(8) -> 4   # 4
class NeighborSum:
    def __init__(self, grid: list[list[int]]):
        pass

    def adjacentSum(self, value: int) -> int:
        pass

    def diagonalSum(self, value: int) -> int:
        pass

Key trick

Precompute each value's position. Then a query checks only four cells instead of searching the grid.

Trap

Check both row and column bounds, especially for values on an edge or corner.

Why is it interesting?

The grid is distinct, consecutive values allow a list-based position lookup, turning repeated queries into constant-time operations.

Python solution

class NeighborSum:
    def __init__(self, grid: list[list[int]]):
        self.grid = grid
        self.n = len(grid)
        self.pos = [(0, 0)] * (self.n * self.n)

        for r in range(self.n):
            for c in range(self.n):
                self.pos[grid[r][c]] = (r, c)

    def _sum(self, value: int, directions: tuple[tuple[int, int], ...]) -> int:
        r, c = self.pos[value]
        total = 0

        for dr, dc in directions:
            nr, nc = r + dr, c + dc
            if 0 <= nr < self.n and 0 <= nc < self.n:
                total += self.grid[nr][nc]

        return total

    def adjacentSum(self, value: int) -> int:
        return self._sum(value, ((-1, 0), (1, 0), (0, -1), (0, 1)))

    def diagonalSum(self, value: int) -> int:
        return self._sum(value, ((-1, -1), (-1, 1), (1, -1), (1, 1)))

Preprocessing takes \(O(n^2)\) time and space. Each query takes \(O(1)\) time.

Comment on my solution

Your solution is correct and has optimal query time. The loop that appends each row to self.grid is unnecessary: assigning self.grid = grid has the same reference-sharing behavior. Also, initializing self.index with zeros is harmless because every entry is replaced, but initializing it with coordinate pairs better reflects its contents.

class NeighborSum:

    def __init__(self, grid: list[list[int]]):
        self.n = len(grid)
        self.grid = []
        self.index = [0] * (self.n * self.n)
        for row in grid:
            self.grid.append(row)
        for r in range(self.n):
            for c in range(self.n):
                self.index[grid[r][c]] = (r,c)

    def adjacentSum(self, value: int) -> int:
        r, c = self.index[value]
        total = 0
        for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < self.n and 0 <= nc < self.n:
                total += self.grid[nr][nc]
        return total

    def diagonalSum(self, value: int) -> int:
        r, c = self.index[value]
        total = 0
        for dr, dc in ((-1, -1), (-1, 1), (1, -1), (1, 1)):
            nr, nc = r + dr, c + dc
            if 0 <= nr < self.n and 0 <= nc < self.n:
                total += self.grid[nr][nc]
        return total