1496. Path Crossing - Explanation

Problem Link



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Hash Set - Used for O(1) lookups to check if a coordinate has been visited
  • Coordinate Systems - Understanding how to represent and track 2D positions

1. Hash Set

Intuition

We start at the origin and follow the path character by character. At each step, we move in the indicated direction. The path crosses itself if we visit a position we've been to before. A hash set provides O(1) lookups to check if a coordinate has been visited.

Algorithm

  1. Initialize a set visit and add the starting position (0, 0).
  2. Initialize coordinates x = 0, y = 0.
  3. For each character in the path:
    • Update x or y based on the direction (N, S, E, W).
    • If the new position exists in visit, return true.
    • Otherwise, add the new position to visit.
  4. If we finish the path without revisiting any position, return false.
class Solution:
    def isPathCrossing(self, path: str) -> bool:
        dir = {
            'N': [0, 1],
            'S': [0, -1],
            'E': [1, 0],
            'W': [-1, 0]
        }

        visit = set()
        x, y = 0, 0

        for c in path:
            visit.add((x, y))
            dx, dy = dir[c]
            x, y = x + dx, y + dy
            if (x, y) in visit:
                return True

        return False

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

2. Hash Set (Custom Hash)

Intuition

Instead of storing coordinates as strings or tuples, we can encode them into a single integer. By shifting one coordinate (e.g., x << 32) and adding the other, we create a unique hash for each position. This can improve performance by avoiding string concatenation overhead.

Algorithm

  1. Define a hash function: hash(x, y) = (x << 32) + y.
  2. Initialize a set and add hash(0, 0).
  3. Track position with x = 0, y = 0.
  4. For each character in the path:
    • Update coordinates based on direction.
    • Compute the hash of the new position.
    • If it exists in the set, return true.
    • Otherwise, add the hash to the set.
  5. Return false if no crossing is found.
class Solution:
    def isPathCrossing(self, path: str) -> bool:
        visit = set()
        x, y = 0, 0
        visit.add(self.hash(x, y))

        for c in path:
            if c == 'N':
                y += 1
            elif c == 'S':
                y -= 1
            elif c == 'E':
                x += 1
            elif c == 'W':
                x -= 1

            pos = self.hash(x, y)
            if pos in visit:
                return True
            visit.add(pos)

        return False

    def hash(self, x: int, y: int) -> int:
        return (x << 32) + y

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

Common Pitfalls

Forgetting to Add the Starting Position

A common mistake is forgetting to add the origin (0, 0) to the visited set before processing the path. The path can cross the starting point, so it must be tracked from the beginning. If you only add positions after moving, you will miss cases where the path returns to the origin.

Incorrect Coordinate Representation

When storing coordinates in a hash set, using improper representations can cause collisions or misses. For example, concatenating coordinates as x + y instead of x + "," + y can produce identical strings for different coordinate pairs (e.g., (1, 23) and (12, 3) both become "123"). Always use a delimiter or tuple representation to ensure uniqueness.