There is an endless straight line populated with some robots and walls. You are given integer arrays robots, distance, and walls:
robots[i] is the position of the ith robot.
distance[i] is the maximum distance the ith robot's bullet can travel.
walls[j] is the position of the jth wall.
Every robot has one bullet that can either fire to the left or the right at most distance[i] meters.
A bullet destroys every wall in its path that lies within its range. Robots are fixed obstacles: if a bullet hits another robot before reaching a wall, it immediately stops at that robot and cannot continue.
Return the maximum number of unique walls that can be destroyed by the robots.
Notes:
A wall and a robot may share the same position; the wall can be destroyed by the robot at that position.
In this example, only robots[0] can reach the wall, but its shot to the right is blocked by robots[1]; thus the answer is 0.
Constraints:
1 <= robots.length == distance.length <= 105
1 <= walls.length <= 105
1 <= robots[i], walls[j] <= 109
1 <= distance[i] <= 105
All values in robots are unique
All values in walls are unique
Solutions
Solution 1: Memoized Search
Thinking
Each robot fires left or right, clipped by its \(\textit{distance}\) and by neighbors. \(2^n\) assignments are impossible.
After sorting by position, robot \(i\)'s choice depends only on robot \(i+1\)'s direction. \(\textit{dfs}(i,j)\) is the best destruction after deciding \(i\) with the next direction equal to \(j\).
A left shot is blocked by the previous robot; a right shot is blocked by the next robot and, if that one also fires left, by its range. Binary search counts walls in the surviving interval; memoization removes duplicate states.
We first store each robot with its range in an array and sort them by robot position. We also sort the wall positions. Next, we use depth-first search (DFS) to calculate the number of walls each robot can destroy, and use memoized search to avoid redundant calculations.
We design a function \(\text{dfs}(i, j)\), where \(i\) represents the index of the current robot being considered, and \(j\) represents the firing direction of the next robot (0 for left, 1 for right), and returns the number of walls that can be destroyed. The answer is \(\text{dfs}(n - 1, 1)\), where \(j\) can be 0 or 1 in the boundary state.
The execution logic of function \(\text{dfs}(i, j)\) is as follows:
If \(i \lt 0\), it means all robots have been considered, return 0.
Otherwise, for the current robot, there are two firing directions to choose from.
If choosing to fire left, we need to calculate the left range \([\text{left}, \text{robot}[i][0]]\), and use binary search to calculate the number of walls that can be destroyed in this range. In this case, a total of \(\text{dfs}(i - 1, 0) + \text{count}\) walls can be destroyed, where \(\text{count}\) is the number of walls destroyed when the current robot fires left.
If choosing to fire right, we need to calculate the right range \([\text{robot}[i][0], \text{right}]\), and use binary search to calculate the number of walls that can be destroyed in this range. In this case, a total of \(\text{dfs}(i - 1, 1) + \text{count}\) walls can be destroyed, where \(\text{count}\) is the number of walls destroyed when the current robot fires right.
The return value of the function is the maximum number of walls that can be destroyed by the two firing directions.
Time complexity \(O(n \times \log n + m \times \log m)\), space complexity \(O(n)\). Where \(n\) and \(m\) are the numbers of robots and walls respectively.
Each robot fires left or right, clipped by its \(\textit{distance}\) and by neighbors. Trying all \(2^n\) assignments does not fit \(n\le 10^5\).
After sorting by position, robot \(i\)'s reachable interval depends only on robot \(i+1\)'s direction. \(f[i][j]\) is the best total through robot \(i\) when that next direction is \(j\): the better of a left shot plus \(f[i-1][0]\) and a right shot plus \(f[i-1][1]\).
Searching that recurrence still chains \(n\) calls and overflows the stack. The two states are filled from \(i=0\) upward, and binary search counts the walls inside each clipped interval.
We first store each robot with its range in an array and sort them by robot position. We also sort the wall positions.
Define \(f[i][j]\) as the number of walls that can be destroyed after considering robot \(i\), when the next robot fires in direction \(j\) (0 for left, 1 for right). The answer is \(f[n - 1][1]\). There is no next robot when \(i = n - 1\), so either value of \(j\) gives the same result. When \(i = 0\) there is no earlier state, and that prefix is 0.
We fill \(f\) for \(i\) from \(0\) to \(n - 1\). For the current robot there are two firing directions.
If it fires left, the range is \([\text{left}, \text{robot}[i][0]]\). Binary search counts the walls in that range. The total is \(f[i - 1][0] + \text{count}\), where \(\text{count}\) is the number of walls this robot destroys by firing left.
If it fires right, the range is \([\text{robot}[i][0], \text{right}]\). Binary search counts the walls in that range. The total is \(f[i - 1][1] + \text{count}\), where \(\text{count}\) is the number of walls this robot destroys by firing right.
\(f[i][j]\) is the larger of those two totals.
Time complexity \(O(n \times \log n + m \times \log m + n \times \log m)\), space complexity \(O(n)\). Where \(n\) and \(m\) are the numbers of robots and walls respectively.