1222. Queens That Can Attack the King
Problem Description
You have an 8x8 chessboard (0-indexed) with multiple black queens and one white king placed on it.
Given:
queens
: A 2D array wherequeens[i] = [xQueen_i, yQueen_i]
represents the position of the i-th black queenking
: An array of length 2 whereking = [xKing, yKing]
represents the position of the white king
Your task is to find all black queens that can directly attack the king.
In chess, a queen can attack any piece that lies in the same row, column, or diagonal (in any of the 8 directions: up, down, left, right, and the four diagonal directions). However, a queen cannot attack through another piece - if there's another queen blocking the path between an attacking queen and the king, only the closest queen to the king in that direction can attack.
The solution works by:
- Storing all queen positions in a set for quick lookup
- From the king's position, searching outward in all 8 possible directions (represented by direction vectors where
a
andb
range from -1 to 1) - For each direction, moving step by step until either:
- A queen is found (add it to the answer and stop searching in that direction)
- The edge of the board is reached
- Only the first queen encountered in each direction can attack the king, as it would block any queens behind it
Return the coordinates of all queens that can attack the king. The order of the returned coordinates doesn't matter.
Intuition
The key insight is to think from the king's perspective rather than checking each queen individually. Instead of asking "which queens can attack the king?", we ask "what can the king see in each direction?"
Think about standing at the king's position and looking outward in all 8 directions. In each direction, you can only be attacked by the first queen you encounter - any queens behind that first one are blocked. This is similar to shining a flashlight in each direction from the king's position; the light stops at the first queen it hits.
This leads us to the approach of radiating outward from the king's position. We need to check all 8 directions: horizontal (left, right), vertical (up, down), and diagonal (4 diagonal directions). These directions can be represented by direction vectors (a, b)
where both a
and b
range from -1 to 1, excluding (0, 0)
which represents no movement.
For each direction, we keep moving one square at a time (x + a, y + b)
until we either:
- Find a queen - this queen can attack the king, so we record it and stop looking further in that direction
- Hit the edge of the board - no queen can attack from this direction
By using a set to store queen positions, we can check in O(1)
time whether a square contains a queen as we traverse each direction. This is much more efficient than checking every queen against every possible attacking path.
The maximum number of queens that can attack the king is 8 (one from each direction), and we only need to traverse at most 7 squares in each direction on an 8x8 board, making this approach very efficient.
Solution Approach
The implementation follows a direct search strategy from the king's position:
Step 1: Store Queen Positions
s = {(i, j) for i, j in queens}
We create a set s
containing tuples of queen positions. Using a set gives us O(1)
lookup time to check if a position contains a queen.
Step 2: Generate Direction Vectors
for a in range(-1, 2):
for b in range(-1, 2):
if a or b:
We iterate through all possible direction combinations where a
and b
can be -1, 0, or 1. This gives us 9 combinations, but we skip (0, 0)
using the condition if a or b
, leaving us with 8 valid directions:
(-1, -1)
: upper-left diagonal(-1, 0)
: up(-1, 1)
: upper-right diagonal(0, -1)
: left(0, 1)
: right(1, -1)
: lower-left diagonal(1, 0)
: down(1, 1)
: lower-right diagonal
Step 3: Search in Each Direction
x, y = king while 0 <= x + a < n and 0 <= y + b < n: x, y = x + a, y + b if (x, y) in s: ans.append([x, y]) break
For each direction:
- Start from the king's position
(x, y)
- Keep moving in the direction
(a, b)
by updatingx = x + a
andy = y + b
- Check boundary conditions
0 <= x + a < n and 0 <= y + b < n
to ensure we stay on the board - If we find a queen at position
(x, y)
(checked using(x, y) in s
):- Add this queen's position to our answer list
- Break out of the while loop since this queen blocks any other queens behind it in this direction
- If we reach the board's edge without finding a queen, the while loop ends naturally
Step 4: Return Results The algorithm returns all queens that can directly attack the king. The maximum size of the answer is 8 (one queen from each direction).
Time Complexity: O(1)
- Since the board size is fixed at 8×8, we check at most 8 directions × 7 squares = 56 positions.
Space Complexity: O(Q)
where Q is the number of queens, for storing the queen positions in the set.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's work through a small example on a 5x5 board (for simplicity) with the king at position [2, 2]
and queens at positions [[0, 0], [0, 2], [1, 1], [3, 4], [4, 2]]
.
Step 1: Visualize the Board
0 1 2 3 4 0 Q . Q . . 1 . Q . . . 2 . . K . . 3 . . . . Q 4 . . Q . .
Step 2: Create Queen Position Set
s = {(0, 0), (0, 2), (1, 1), (3, 4), (4, 2)}
Step 3: Search from King's Position in All 8 Directions
Starting from king at [2, 2]
, we check each direction:
-
Direction (-1, -1) (upper-left diagonal):
- Move to
[1, 1]
→ Found queen! Add[1, 1]
to answer and stop.
- Move to
-
Direction (-1, 0) (up):
- Move to
[1, 2]
→ No queen - Move to
[0, 2]
→ Found queen! Add[0, 2]
to answer and stop.
- Move to
-
Direction (-1, 1) (upper-right diagonal):
- Move to
[1, 3]
→ No queen - Move to
[0, 4]
→ No queen, reached edge.
- Move to
-
Direction (0, -1) (left):
- Move to
[2, 1]
→ No queen - Move to
[2, 0]
→ No queen, reached edge.
- Move to
-
Direction (0, 1) (right):
- Move to
[2, 3]
→ No queen - Move to
[2, 4]
→ No queen, reached edge.
- Move to
-
Direction (1, -1) (lower-left diagonal):
- Move to
[3, 1]
→ No queen - Move to
[4, 0]
→ No queen, reached edge.
- Move to
-
Direction (1, 0) (down):
- Move to
[3, 2]
→ No queen - Move to
[4, 2]
→ Found queen! Add[4, 2]
to answer and stop.
- Move to
-
Direction (1, 1) (lower-right diagonal):
- Move to
[3, 3]
→ No queen - Move to
[4, 4]
→ No queen, reached edge.
- Move to
Step 4: Result
The queens that can attack the king are: [[1, 1], [0, 2], [4, 2]]
Note that:
- Queen at
[0, 0]
cannot attack because[1, 1]
blocks the diagonal path - Queen at
[3, 4]
cannot attack because it's not on the same row, column, or diagonal as the king
This demonstrates how the algorithm efficiently finds only the closest queen in each direction that can attack the king.
Solution Implementation
1class Solution:
2 def queensAttacktheKing(
3 self, queens: List[List[int]], king: List[int]
4 ) -> List[List[int]]:
5 # Board size for standard chess board
6 BOARD_SIZE = 8
7
8 # Convert queens list to a set of tuples for O(1) lookup
9 queen_positions = {(row, col) for row, col in queens}
10
11 # Result list to store queens that can attack the king
12 attacking_queens = []
13
14 # Check all 8 directions: horizontal, vertical, and diagonal
15 for row_direction in range(-1, 2):
16 for col_direction in range(-1, 2):
17 # Skip the case where both directions are 0 (no movement)
18 if row_direction == 0 and col_direction == 0:
19 continue
20
21 # Start from king's position
22 current_row, current_col = king
23
24 # Move in the current direction until we hit a boundary or find a queen
25 while (0 <= current_row + row_direction < BOARD_SIZE and
26 0 <= current_col + col_direction < BOARD_SIZE):
27 # Move one step in the current direction
28 current_row += row_direction
29 current_col += col_direction
30
31 # Check if there's a queen at this position
32 if (current_row, current_col) in queen_positions:
33 # Found the first queen in this direction - it can attack the king
34 attacking_queens.append([current_row, current_col])
35 break # Stop searching in this direction
36
37 return attacking_queens
38
1class Solution {
2 public List<List<Integer>> queensAttacktheKing(int[][] queens, int[] king) {
3 // Chess board size constant
4 final int BOARD_SIZE = 8;
5
6 // Create a 2D boolean array to mark queen positions on the board
7 boolean[][] hasQueen = new boolean[BOARD_SIZE][BOARD_SIZE];
8
9 // Mark all queen positions as true in the board
10 for (int[] queen : queens) {
11 hasQueen[queen[0]][queen[1]] = true;
12 }
13
14 // Result list to store queens that can attack the king
15 List<List<Integer>> attackingQueens = new ArrayList<>();
16
17 // Check all 8 directions from the king's position
18 // directionX and directionY represent the 8 possible directions:
19 // (-1,-1) (-1,0) (-1,1)
20 // (0,-1) KING (0,1)
21 // (1,-1) (1,0) (1,1)
22 for (int directionX = -1; directionX <= 1; directionX++) {
23 for (int directionY = -1; directionY <= 1; directionY++) {
24 // Skip the case where both directions are 0 (king's own position)
25 if (directionX == 0 && directionY == 0) {
26 continue;
27 }
28
29 // Start from the king's adjacent cell in the current direction
30 int currentX = king[0] + directionX;
31 int currentY = king[1] + directionY;
32
33 // Continue moving in the current direction until out of bounds
34 while (currentX >= 0 && currentX < BOARD_SIZE &&
35 currentY >= 0 && currentY < BOARD_SIZE) {
36
37 // If a queen is found in this direction, add it to result
38 if (hasQueen[currentX][currentY]) {
39 attackingQueens.add(List.of(currentX, currentY));
40 break; // Stop searching further in this direction
41 }
42
43 // Move to the next cell in the same direction
44 currentX += directionX;
45 currentY += directionY;
46 }
47 }
48 }
49
50 return attackingQueens;
51 }
52}
53
1class Solution {
2public:
3 vector<vector<int>> queensAttacktheKing(vector<vector<int>>& queens, vector<int>& king) {
4 // Chess board size
5 const int BOARD_SIZE = 8;
6
7 // Create a 2D boolean array to mark queen positions
8 bool hasQueen[8][8]{};
9
10 // Mark all queen positions on the board
11 for (auto& queen : queens) {
12 hasQueen[queen[0]][queen[1]] = true;
13 }
14
15 // Store queens that can attack the king
16 vector<vector<int>> attackingQueens;
17
18 // Check all 8 directions from the king's position
19 // Direction vectors: (-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)
20 for (int deltaRow = -1; deltaRow <= 1; ++deltaRow) {
21 for (int deltaCol = -1; deltaCol <= 1; ++deltaCol) {
22 // Skip the case where both deltas are 0 (king's own position)
23 if (deltaRow == 0 && deltaCol == 0) {
24 continue;
25 }
26
27 // Start from king's position and move in the current direction
28 int currentRow = king[0] + deltaRow;
29 int currentCol = king[1] + deltaCol;
30
31 // Continue moving in this direction until we hit a queen or board boundary
32 while (currentRow >= 0 && currentRow < BOARD_SIZE &&
33 currentCol >= 0 && currentCol < BOARD_SIZE) {
34
35 // If we find a queen in this direction, it can attack the king
36 if (hasQueen[currentRow][currentCol]) {
37 attackingQueens.push_back({currentRow, currentCol});
38 break; // Stop searching in this direction after finding the first queen
39 }
40
41 // Move to the next position in the same direction
42 currentRow += deltaRow;
43 currentCol += deltaCol;
44 }
45 }
46 }
47
48 return attackingQueens;
49 }
50};
51
1/**
2 * Finds all queens that can directly attack the king on an 8x8 chessboard
3 * @param queens - Array of queen positions [row, col]
4 * @param king - King position [row, col]
5 * @returns Array of queen positions that can attack the king
6 */
7function queensAttacktheKing(queens: number[][], king: number[]): number[][] {
8 // Chessboard size (8x8)
9 const BOARD_SIZE = 8;
10
11 // Create a 2D boolean array to mark queen positions
12 const isQueenPresent: boolean[][] = Array.from(
13 { length: BOARD_SIZE },
14 () => Array.from({ length: BOARD_SIZE }, () => false)
15 );
16
17 // Mark all queen positions on the board
18 queens.forEach(([row, col]) => {
19 isQueenPresent[row][col] = true;
20 });
21
22 // Store queens that can attack the king
23 const attackingQueens: number[][] = [];
24
25 // Check all 8 directions from the king's position
26 // Directions: up, down, left, right, and 4 diagonals
27 for (let rowDirection = -1; rowDirection <= 1; rowDirection++) {
28 for (let colDirection = -1; colDirection <= 1; colDirection++) {
29 // Skip the case where both directions are 0 (no movement)
30 if (rowDirection === 0 && colDirection === 0) {
31 continue;
32 }
33
34 // Start from the next position in the current direction
35 let currentRow = king[0] + rowDirection;
36 let currentCol = king[1] + colDirection;
37
38 // Continue moving in this direction until out of bounds
39 while (currentRow >= 0 && currentRow < BOARD_SIZE &&
40 currentCol >= 0 && currentCol < BOARD_SIZE) {
41
42 // If a queen is found in this direction, it can attack the king
43 if (isQueenPresent[currentRow][currentCol]) {
44 attackingQueens.push([currentRow, currentCol]);
45 break; // Only the first queen in this direction can attack
46 }
47
48 // Move to the next position in the same direction
49 currentRow += rowDirection;
50 currentCol += colDirection;
51 }
52 }
53 }
54
55 return attackingQueens;
56}
57
Time and Space Complexity
The time complexity is O(n²)
, and the space complexity is O(n²)
. In this problem, n = 8
.
Time Complexity Analysis:
- Converting the queens list to a set takes
O(q)
time whereq
is the number of queens - The nested loops iterate through 8 directions (from -1 to 1 for both
a
andb
, excluding (0,0)) - For each direction, we traverse at most
n
cells on the board until we hit a boundary or find a queen - Therefore, the total operations are
8 × n
=O(n)
- However, since we need to convert queens to a set first, and in the worst case
q
can beO(n²)
(all cells could have queens), the overall time complexity isO(n²)
Space Complexity Analysis:
- The set
s
stores all queen positions, which in the worst case could be alln²
positions on the board, requiringO(n²)
space - The answer list
ans
can store at most 8 queens (one in each direction from the king), which isO(1)
- Therefore, the overall space complexity is
O(n²)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Direction Generation Logic
A frequent mistake is using if a and b
instead of if a or b
when filtering out the (0, 0) direction. This would incorrectly skip the four cardinal directions (up, down, left, right) where either a
or b
is 0.
Incorrect:
for a in range(-1, 2):
for b in range(-1, 2):
if a and b: # Wrong! This only includes diagonals
Correct:
for a in range(-1, 2):
for b in range(-1, 2):
if a or b: # Correct - excludes only (0, 0)
2. Modifying Loop Variables Inside the While Loop
A critical error is reusing the king's position variables directly in the while loop, which causes the search to start from the wrong position for subsequent directions.
Incorrect:
x, y = king
for a in range(-1, 2):
for b in range(-1, 2):
if a or b:
while 0 <= x + a < 8 and 0 <= y + b < 8:
x, y = x + a, y + b # Modifies x, y permanently!
if (x, y) in s:
ans.append([x, y])
break
Correct:
for a in range(-1, 2):
for b in range(-1, 2):
if a or b:
x, y = king # Reset to king's position for each direction
while 0 <= x + a < 8 and 0 <= y + b < 8:
x, y = x + a, y + b
if (x, y) in s:
ans.append([x, y])
break
3. Using List Instead of Set for Queen Positions
Checking if a position contains a queen using a list results in O(Q) lookup time per check, significantly slowing down the algorithm.
Inefficient:
# O(Q) lookup for each position check
for a in range(-1, 2):
for b in range(-1, 2):
if a or b:
x, y = king
while 0 <= x + a < 8 and 0 <= y + b < 8:
x, y = x + a, y + b
if [x, y] in queens: # O(Q) operation!
ans.append([x, y])
break
Efficient:
# O(1) lookup using set queen_positions = {(row, col) for row, col in queens} # ... then use (x, y) in queen_positions
4. Forgetting to Break After Finding a Queen
Without the break statement, the search continues past the first queen found, potentially adding queens that are blocked and cannot actually attack the king.
Incorrect:
while 0 <= x + a < 8 and 0 <= y + b < 8: x, y = x + a, y + b if (x, y) in s: ans.append([x, y]) # Missing break! Would continue searching and find blocked queens
5. Off-by-One Errors in Boundary Checking
Using <=
instead of <
for the upper boundary check causes index out of bounds errors.
Incorrect:
while 0 <= x + a <= 8 and 0 <= y + b <= 8: # Wrong! Position 8 is out of bounds
Correct:
while 0 <= x + a < 8 and 0 <= y + b < 8: # Correct boundary check
Which data structure is used to implement priority queue?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!