Draw Overlapping ASCII Rectangles
Reported by candidates from Amperity's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Amperity reported this one in July 2025, and the catch is in the constraints: rectangle widths and heights go up to 10^9 while the canvas holds at most 2 * 10^5 cells. If you're taking this OA soon, the naive paint-every-cell loop is the trap. It's a simulation problem with clipping, and the real work is deciding which cells to touch. Border versus interior must be judged from the original unclipped rectangle, which trips people up. StealthCoder sits invisibly on your screen as a safety net if you blank on the clipping math during the live assessment.
The problem
Draw a sequence of ASCII rectangles on a finite canvas. The canvas has canvasWidth columns and canvasHeight rows and is initially filled with the one-character string background. Coordinates use a top-left origin: x increases to the right and y increases downward. Each rectangles[i] is [x, y, width, height]. Its boundary uses borderChars[i], while cells strictly inside the boundary use fillChars[i]. A rectangle whose width or height is 1 consists entirely of boundary cells. Draw rectangles in input order. A later rectangle overwrites every earlier character at each canvas cell it covers. Clip drawing to the canvas: cells of a rectangle outside the canvas are ignored, but whether a visible cell is boundary or interior is determined from the rectangle's original, unclipped dimensions. Return the final canvas as canvasHeight strings ordered from top row to bottom row, each containing exactly canvasWidth characters. Function drawRectangles(canvasWidth: int, canvasHeight: int, background: String, rectangles: int[][], borderChars: String[], fillChars: String[]) → String[] Examples Example 1 canvasWidth = 6 canvasHeight = 5 background = "." rectangles = [[1,1,4,3]] borderChars = ["#"] fillChars = ["+"] return = ["......",".####.",".#++#.",".####.","......"] The rectangle occupies columns 1 through 4 and rows 1 through 3. Its outer cells use #, and its two interior cells use +. Example 2 canvasWidth = 7 canvasHeight = 5 background = "." rectangles = [[1,1,5,3],[4,0,4,4]] borderChars = ["#","@"] fillChars = ["+","o"] return = ["....@@@",".###@oo",".#++@oo",".###@@@","......."] The second rectangle is drawn last, so it overwrites the first rectangle in their overlap. Its rightmost column lies outside the canvas and is clipped; the remaining visible cells keep their boundary or interior role from the original rectangle. Example 3 canvasWidth = 4 canvasHeight = 3 background = "_" rectangles = [[-2,-1,3,3],[2,1,1,2]] borderChars = ["X","|"] fillChars = ["o","!"] return = ["X___","X_|_","__|_"] Only the right boundary of the first rectangle reaches the canvas. The second rectangle has width 1, so both of its visible cells use its boundary character. Constraints 1 <= canvasWidth, canvasHeight and canvasWidth * canvasHeight <= 2 * 10^5. 0 <= rectangles.length <= 10^4. Each rectangles[i] is [x, y, width, height], where -10^9 <= x, y <= 10^9 and 1 <= width, height <= 10^9. borderChars.length == fillChars.length == rectangles.length. background, every borderChars[i], and every fillChars[i] is a one-character printable ASCII string other than a line break. For every rectangle, borderChars[i] != fillChars[i]. Rectangles are drawn in input order and clipped to the canvas.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is to clip each rectangle to the canvas before looping. Compute x0 = max(x, 0), x1 = min(x + width - 1, canvasWidth - 1), and the same for y. If the range is empty, skip it. Then loop only over the visible cells. For each cell, check against the original bounds: it's a border if col == x or col == x + width - 1 or row == y or row == y + height - 1, otherwise it's interior. Never use the clipped edges for that test, or you'll draw fake borders at the canvas edge (Example 3 catches this). Worst case is 10^4 rectangles times 2 * 10^5 cells, which is 2 * 10^9, so be aware of it. Later rectangles overwrite earlier ones, so processing in input order is enough. If the clipping logic slips under pressure, StealthCoder can give you the reference version during the live OA.
Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.
You can drill Draw Overlapping ASCII Rectangles cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.
Get StealthCoderYou've seen the question.
Make sure you actually pass Amperity's OA.
Amperity reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Draw Overlapping ASCII Rectangles FAQ
What's the trick in the Amperity ASCII rectangles problem?+
Clip each rectangle to the canvas bounds first, then iterate only the visible cells. Decide border or interior using the original unclipped x, y, width, and height. Coordinates can reach 10^9, so looping over the full rectangle will time out.
How hard is this problem really?+
Medium-ish, but mostly because of edge cases rather than an algorithm. There's no data structure to learn. The difficulty is off-by-one errors in clipping, negative coordinates, and width or height of 1 where every cell is boundary.
Why can't I just paint each rectangle cell by cell?+
Width and height go up to 10^9, so a full loop is impossible. You must intersect the rectangle with the canvas range, which holds at most 2 * 10^5 cells, and iterate over just that overlap.
How do I handle width or height of 1?+
Your border test handles it naturally. If width is 1, then col == x and col == x + width - 1 are the same column, so every cell matches the border condition. Same for height 1. No special case is needed.
How should I prepare for this in 48 hours?+
Practice grid simulation with bounds clipping. Write the max/min intersection by hand, test the three examples, and try negative origins and rectangles fully off canvas. Also confirm you return exactly canvasHeight strings of canvasWidth characters.