# 3242. Design Neighbor Sum Service

## Description

You are given a n x n 2D array grid containing distinct elements in the range [0, n2 - 1].

Implement the NeighborSum class:

• NeighborSum(int [][]grid) initializes the object.
• int adjacentSum(int value) returns the sum of elements which are adjacent neighbors of value, that is either to the top, left, right, or bottom of value in grid.
• int diagonalSum(int value) returns the sum of elements which are diagonal neighbors of value, that is either to the top-left, top-right, bottom-left, or bottom-right of value in grid.

Example 1:

Input:

[[[[0, 1, 2], [3, 4, 5], [6, 7, 8]]], [1], [4], [4], [8]]

Output: [null, 6, 16, 16, 4]

Explanation:

• The adjacent neighbors of 1 are 0, 2, and 4.
• The adjacent neighbors of 4 are 1, 3, 5, and 7.
• The diagonal neighbors of 4 are 0, 2, 6, and 8.
• The diagonal neighbor of 8 is 4.

Example 2:

Input:

[[[[1, 2, 0, 3], [4, 7, 15, 6], [8, 9, 10, 11], [12, 13, 14, 5]]], [15], [9]]

Output: [null, 23, 45]

Explanation:

• The adjacent neighbors of 15 are 0, 10, 7, and 6.
• The diagonal neighbors of 9 are 4, 12, 14, and 15.

Constraints:

• 3 <= n == grid.length == grid[0].length <= 10
• 0 <= grid[i][j] <= n2 - 1
• All grid[i][j] are distinct.
• value in adjacentSum and diagonalSum will be in the range [0, n2 - 1].
• At most 2 * n2 calls will be made to adjacentSum and diagonalSum.

## Solutions

### Solution 1: Hash Table

We can use a hash table $\textit{d}$ to store the coordinates of each element. Then, according to the problem description, we separately calculate the sum of adjacent elements and diagonally adjacent elements.

In terms of time complexity, initializing the hash table has a time complexity of $O(m \times n)$, and calculating the sum of adjacent elements and diagonally adjacent elements has a time complexity of $O(1)$. The space complexity is $O(m \times n)$.

• class neighborSum {
private int[][] grid;
private final Map<Integer, int[]> d = new HashMap<>();
private final int[][] dirs = { {-1, 0, 1, 0, -1}, {-1, 1, 1, -1, -1} };

public neighborSum(int[][] grid) {
this.grid = grid;
int m = grid.length, n = grid[0].length;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
d.put(grid[i][j], new int[] {i, j});
}
}
}

return cal(value, 0);
}

public int diagonalSum(int value) {
return cal(value, 1);
}

private int cal(int value, int k) {
int[] p = d.get(value);
int s = 0;
for (int q = 0; q < 4; ++q) {
int x = p[0] + dirs[k][q], y = p[1] + dirs[k][q + 1];
if (x >= 0 && x < grid.length && y >= 0 && y < grid[0].length) {
s += grid[x][y];
}
}
return s;
}
}

/**
* Your neighborSum object will be instantiated and called as such:
* neighborSum obj = new neighborSum(grid);
* int param_2 = obj.diagonalSum(value);
*/


• class neighborSum {
public:
neighborSum(vector<vector<int>>& grid) {
this->grid = grid;
int m = grid.size(), n = grid[0].size();
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
d[grid[i][j]] = {i, j};
}
}
}

return cal(value, 0);
}

int diagonalSum(int value) {
return cal(value, 1);
}

private:
vector<vector<int>> grid;
unordered_map<int, pair<int, int>> d;
int dirs[2][5] = { {-1, 0, 1, 0, -1}, {-1, 1, 1, -1, -1} };

int cal(int value, int k) {
auto [i, j] = d[value];
int s = 0;
for (int q = 0; q < 4; ++q) {
int x = i + dirs[k][q], y = j + dirs[k][q + 1];
if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size()) {
s += grid[x][y];
}
}
return s;
}
};

/**
* Your neighborSum object will be instantiated and called as such:
* neighborSum* obj = new neighborSum(grid);
* int param_2 = obj->diagonalSum(value);
*/


• class neighborSum:

def __init__(self, grid: List[List[int]]):
self.grid = grid
self.d = {}
self.dirs = ((-1, 0, 1, 0, -1), (-1, 1, 1, -1, -1))
for i, row in enumerate(grid):
for j, x in enumerate(row):
self.d[x] = (i, j)

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

def cal(self, value: int, k: int):
i, j = self.d[value]
s = 0
for a, b in pairwise(self.dirs[k]):
x, y = i + a, j + b
if 0 <= x < len(self.grid) and 0 <= y < len(self.grid[0]):
s += self.grid[x][y]
return s

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

# Your neighborSum object will be instantiated and called as such:
# obj = neighborSum(grid)
# param_2 = obj.diagonalSum(value)


• type neighborSum struct {
grid [][]int
d    map[int][2]int
dirs [2][5]int
}

func Constructor(grid [][]int) neighborSum {
d := map[int][2]int{}
for i, row := range grid {
for j, x := range row {
d[x] = [2]int{i, j}
}
}
dirs := [2][5]int{ {-1, 0, 1, 0, -1}, {-1, 1, 1, -1, -1} }
return neighborSum{grid, d, dirs}
}

func (this *neighborSum) AdjacentSum(value int) int {
return this.cal(value, 0)
}

func (this *neighborSum) DiagonalSum(value int) int {
return this.cal(value, 1)
}

func (this *neighborSum) cal(value, k int) int {
p := this.d[value]
s := 0
for q := 0; q < 4; q++ {
x, y := p[0]+this.dirs[k][q], p[1]+this.dirs[k][q+1]
if x >= 0 && x < len(this.grid) && y >= 0 && y < len(this.grid[0]) {
s += this.grid[x][y]
}
}
return s
}

/**
* Your neighborSum object will be instantiated and called as such:
* obj := Constructor(grid);
* param_2 := obj.DiagonalSum(value);
*/


• class neighborSum {
private grid: number[][];
private d: Map<number, [number, number]> = new Map();
private dirs: number[][] = [
[-1, 0, 1, 0, -1],
[-1, 1, 1, -1, -1],
];
constructor(grid: number[][]) {
for (let i = 0; i < grid.length; ++i) {
for (let j = 0; j < grid[0].length; ++j) {
this.d.set(grid[i][j], [i, j]);
}
}
this.grid = grid;
}

return this.cal(value, 0);
}

diagonalSum(value: number): number {
return this.cal(value, 1);
}

cal(value: number, k: number): number {
const [i, j] = this.d.get(value)!;
let s = 0;
for (let q = 0; q < 4; ++q) {
const [x, y] = [i + this.dirs[k][q], j + this.dirs[k][q + 1]];
if (x >= 0 && x < this.grid.length && y >= 0 && y < this.grid[0].length) {
s += this.grid[x][y];
}
}
return s;
}
}

/**
* Your neighborSum object will be instantiated and called as such:
* var obj = new neighborSum(grid)