Skip to content
← All posts

Queens That Can Attack the King: Direction Scanning

5 min read
leetcodeproblemmediumarraysmatrixsimulation

On an 8x8 chessboard, you are given the positions of black queens and one white king. Return the coordinates of all queens that can directly attack the king. A queen can attack along its row, column, or any diagonal, but only if no other queen is blocking the path between them.

This is LeetCode 1222: Queens That Can Attack the King.

QQQQKQQQ
Red = queens that can attack the king. Blue = king at (3,4). Orange = attack paths. The queen at (7,3) cannot attack because it is not aligned with the king in any of the 8 directions.

Why this problem matters

The 8-direction scanning pattern shows up in many grid problems. Any time you need to look outward from a point along rows, columns, and diagonals, you are using the same idea. Chess problems, word search, and "nearest obstacle" problems all rely on it. Once the pattern is automatic, you can apply it to any grid problem that involves line-of-sight or directional traversal.

The key insight

Your first instinct might be to check each queen and see if it can reach the king. That works, but you have to trace the path from each queen back to the king to check for blockers. There is a simpler approach: scan outward from the king in all 8 directions. The first queen you encounter in each direction is one that can attack. Any queen behind it is blocked.

This flips the problem from "which queens reach the king" to "what does the king see in each direction." Since the board is fixed at 8x8, each direction scan visits at most 7 cells. Eight directions times seven cells gives a constant amount of work.

The solution

def queens_attack_the_king(queens, king):
    queen_set = set(map(tuple, queens))
    result = []
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1),
                  (-1, -1), (-1, 1), (1, -1), (1, 1)]

    for dr, dc in directions:
        r, c = king
        while True:
            r += dr
            c += dc
            if r < 0 or r > 7 or c < 0 or c > 7:
                break
            if (r, c) in queen_set:
                result.append([r, c])
                break

    return result

The algorithm starts from the king and walks outward in each of the 8 directions. For each direction, it steps one cell at a time. If it finds a queen, it adds that queen to the result and stops scanning that direction. If it walks off the board, it moves on to the next direction.

The queen_set is a hash set that gives O(1) lookups. Without it, you would need to scan the queen list for every cell you visit, which adds unnecessary overhead.

The break after finding a queen is what handles the "blocking" logic. You only care about the first queen in each direction. Any queens further along that line are irrelevant because the first queen blocks the path.

When you need to find the nearest item in a direction, scan outward from the target rather than inward from each candidate. This avoids the complexity of checking whether other items block the path.

Visual walkthrough

Let's trace through the algorithm step by step. The king is at (3,4) and seven queens are scattered across the board. Watch how scanning from the king finds the first queen in each direction.

Step 1: Store queen positions in a set for O(1) lookup

QQQQKQQQ

Convert the queen list to a set of coordinates. We will scan outward from the king at (3,4) in all 8 directions.

Step 2: Scan north (dr=-1, dc=0). Queen found at (0,4).

QQQQKQQQ

From (3,4) upward: (2,4) empty, (1,4) empty, (0,4) has a queen. Add (0,4) to results and stop.

Step 3: Scan west (dr=0, dc=-1). Queen found at (3,0).

QQQQKQQQ

From (3,4) left: (3,3), (3,2), (3,1) all empty, (3,0) has a queen. Add (3,0) to results.

Step 4: Scan diagonals. NE finds (1,6), NW finds (0,1), SW finds (5,2).

QQQQKQQQ

NE: (2,5) empty, (1,6) queen. NW: (2,3) empty, (1,2) empty, (0,1) queen. SW: (4,3) empty, (5,2) queen. SE: no queen before the board edge.

Step 5: Scan south (dr=1, dc=0). Queen found at (5,4). All 8 directions done.

QQQQKQQQ

South: (4,4) empty, (5,4) queen. Result: 6 queens can attack. The queen at (7,3) is not aligned with the king in any direction.

Six of the seven queens can attack the king. The queen at (7,3) cannot because it is not aligned with the king along any row, column, or diagonal. The scanning approach finds all six attackers without ever needing to check the blocked queen.

Complexity analysis

ApproachTimeSpace
Direction scan from kingO(1)O(Q) for queen set

Time is O(1) because the board is always 8x8. We scan 8 directions, and each direction visits at most 7 cells. That is 8 * 7 = 56 cell checks at most, which is a constant. The initial set construction is O(Q) where Q is the number of queens, but Q is at most 63, so that is also effectively constant.

Space is O(Q) for the hash set of queen positions. On an 8x8 board, Q is at most 63, so this is bounded by a constant. The result list holds at most 8 queens (one per direction).

The building blocks

1. Eight-direction traversal

directions = [(-1, 0), (1, 0), (0, -1), (0, 1),
              (-1, -1), (-1, 1), (1, -1), (1, 1)]

for dr, dc in directions:
    r, c = start_r, start_c
    while 0 <= r + dr <= 7 and 0 <= c + dc <= 7:
        r += dr
        c += dc

This is the standard pattern for scanning all 8 directions from a point on a grid. The direction vectors cover north, south, west, east, and the four diagonals. You will reuse this exact pattern in problems like N-Queens constraint checking, bishop attack detection, and word search in all directions.

2. Set-based lookup for positions

queen_set = set(map(tuple, queens))

if (r, c) in queen_set:
    result.append([r, c])
    break

Converting a list of positions to a set lets you check "is there a piece at this cell?" in O(1) time. The alternative, scanning the list each time, would be O(Q) per check. This pattern appears any time you need fast membership tests on grid coordinates, for example checking obstacles, walls, or visited cells.

Edge cases

  • No queens on the board: the result is an empty list. Every direction scan walks to the edge without finding anything.
  • Queens in all 8 directions: the result contains 8 queens, one per direction. This is the maximum possible.
  • Multiple queens along the same line: only the closest one to the king is returned. The first break ensures queens behind it are ignored.
  • King in a corner: only 3 directions stay on the board (2 cardinal, 1 diagonal). The other 5 directions immediately go out of bounds.
  • King on an edge but not a corner: 5 directions stay on the board. The remaining 3 go out of bounds after the first step.
  • All queens are on the same row or column: at most 2 can attack (one from each side of the king along that line).

From understanding to recall

The direction scanning pattern is easy to understand but surprisingly easy to get wrong under pressure. Do you remember all 8 direction vectors? Do you handle the board boundary check before or after stepping? Do you break after finding the first queen or after adding it? These details matter, and they are exactly the kind of thing you forget when you are nervous.

Spaced repetition turns understanding into reflex. You write the 8-direction loop from memory, get the boundary check right, and handle the early termination correctly. After a few sessions, scanning from a target outward becomes something you do without thinking. The next time a grid problem asks "what can this cell see," the code writes itself.

Related posts

CodeBricks breaks Queens That Can Attack the King into its direction scanning and set lookup building blocks, then drills them with spaced repetition until the pattern is automatic. You type the 8-direction loop and the scan-until-found logic from memory until there is no hesitation. When a matrix problem appears in your interview, you do not pause to think about direction vectors. You just write them.