Implement ASCII canvas and solve two data problems
Company: Asana
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This multi-part question evaluates implementation and algorithmic competencies such as managing a mutable ASCII canvas and rendering, in-place array algorithms for the product-excluding-self problem under O(n) time and O(1) extra space, and external-memory parsing and frequency counting for very large log files, including correctness and edge-case handling. It is commonly asked because it tests practical coding ability, correctness under resource constraints, parsing/IO trade-offs and complexity reasoning; the category is Coding & Algorithms with file/systems aspects, and the level of abstraction spans practical implementation and conceptual algorithmic understanding.
Part 1: Fixed ASCII Canvas Renderer
Constraints
- Canvas size is fixed: width = 10 and height = 6.
- 0 <= number of operations <= 10^5.
- For 'rect', ch is a single ASCII character.
- For 'rect' and 'erase', normalize reversed coordinates and clip to the canvas.
- For 'move', if source or destination is out of bounds, ignore the operation.
Examples
Input: []
Expected Output: ['..........', '..........', '..........', '..........', '..........', '..........']
Explanation: Edge case: no operations leaves the canvas empty.
Input: [('rect', '#', 1, 1, 3, 2)]
Expected Output: ['..........', '.###......', '.###......', '..........', '..........', '..........']
Explanation: Draws a filled 3 x 2 rectangle using inclusive coordinates.
Input: [('rect', 'A', 0, 0, 0, 0), ('rect', 'B', 2, 0, 2, 0), ('move', 0, 0, 2, 0)]
Expected Output: ['..A.......', '..........', '..........', '..........', '..........', '..........']
Explanation: The A at (0,0) moves to (2,0), overwriting B, and the source becomes empty.
Input: [('rect', 'X', -2, -1, 2, 1), ('erase', 1, 0, 1, 0)]
Expected Output: ['..X.......', '..X.......', '..........', '..........', '..........', '..........']
Explanation: The rectangle is clipped to the canvas, then the erase area uses reversed coordinates and clears the left two columns.
Hints
- A 2D list of characters is enough because the canvas size never changes.
- Before drawing or erasing, sort the x values and y values, then clip them to the valid range.
Part 2: Product of Array Except Self
Constraints
- 0 <= len(nums) <= 10^5.
- -30 <= nums[i] <= 30.
- Do not use division.
- Use only O(1) extra space beyond the output array.
Examples
Input: []
Expected Output: []
Explanation: Edge case: an empty array returns an empty array.
Input: [5]
Expected Output: [1]
Explanation: With one element, the product of all other elements is the empty product, which is 1.
Input: [1, 2, 3, 4]
Expected Output: [24, 12, 8, 6]
Explanation: Standard example using prefix and suffix products.
Input: [0, 1, 2, 3]
Expected Output: [6, 0, 0, 0]
Explanation: Only the position containing 0 gets the product of the non-zero values.
Input: [0, 0, 5]
Expected Output: [0, 0, 0]
Explanation: With two zeros, every position has at least one zero in its product.
Hints
- For each position, you need the product of everything to its left and everything to its right.
- You can store prefix products directly in the output array, then multiply by a running suffix product in a backward pass.
Part 3: Count Valid IPv4 Addresses in Log Lines
Constraints
- 0 <= len(lines) <= 10^5 in tests.
- The total number of characters can be large, so scan line by line.
- Valid IPv4 format is a.b.c.d with exactly 4 octets.
- Each octet must be in [0, 255].
- Octets with leading zeros, such as 01 or 001, are invalid unless the octet is exactly 0.
- For this coding task, assume the final set of distinct valid IPs fits in memory.
Examples
Input: ['src=10.0.0.1 dst=192.168.1.2', 'retry from 10.0.0.1', 'mirror 10.0.0.1']
Expected Output: [('10.0.0.1', 3), ('192.168.1.2', 1)]
Explanation: The IP 10.0.0.1 appears three times, and 192.168.1.2 appears once.
Input: ['bad 256.1.1.1 good 1.2.3.4', 'skip 01.2.3.4 and 1.2.3', 'also 1.2.3.4.5 no']
Expected Output: [('1.2.3.4', 1)]
Explanation: 256.1.1.1 is out of range, 01.2.3.4 has a leading zero, 1.2.3 has too few parts, and 1.2.3.4.5 has too many parts.
Input: ['0.0.0.0 255.255.255.255 0.0.0.0']
Expected Output: [('0.0.0.0', 2), ('255.255.255.255', 1)]
Explanation: Both boundary IPs are valid, and 0.0.0.0 appears twice.
Input: []
Expected Output: []
Explanation: Edge case: no lines means no IP occurrences.
Hints
- First extract digit-and-dot runs from each line, then validate which ones are exactly 4 octets.
- A hash map is enough for counting; sort only once at the end.