FastPrepBitFont Part 3 - Decode Run-Length-Encoded Rows

BitFont Part 3 - Decode Run-Length-Encoded Rows

Stripe logoStripe● MediumFULLTIMENEW GRADINTERNONSITE INTERVIEW
Learn

Problem statement

In the BitFont exercise, IBM Plex Serif 14 glyph rows are stored with run-length encoding. Decode every supplied row into its full bitmap representation as a string of 0 and 1 pixels.

Each character in an encoded row gives one run length:

  • 0-9 represent lengths 0-9.
  • a-z represent lengths 10-35, so a is 10, b is 11, and so on.

Decode each row from left to right. The first run contains white pixels, represented by 0. After every encoded character, alternate between white (0) and black (1) for the next run.

A zero-length run appends no pixels, but it still changes the pixel value used by the next run. Return the decoded rows in the same order as the input.

Practice sequence

  1. Part 1: Render a Character
  2. Part 2: Render a Word
  3. Part 3: Decode Run-Length-Encoded Rows (current)

Reversible codec follow-up

Keep the decoding behavior above for every ordinary encoded row. To practice both directions of the codec in the same function, an entry in encodedRows may instead contain one of these tagged commands. Return one string for each entry, in input order; entries do not share state.

  • encode:bits: encode the binary pixel row bits using the canonical encoding below, and return the encoded row.
  • decode:packed: decode packed using the original rules, and return the binary pixel row.
  • render:packed: decode packed, then return the row with each 0 displayed as . and each 1 displayed as #.
  • roundtrip:bits: encode bits, decode the result, and render the recovered row with the same . and # mapping.

The command prefixes are practice serialization. Their colon is not part of the original run alphabet, so an untagged row always keeps its original meaning. Payloads may be empty. All supplied entries satisfy the rules; no invalid-input error result is required.

Canonical encoding

  1. Encode each maximal consecutive run of equal binary pixels. Use the same digit-and-letter count alphabet and white-first alternating states as the decoder.
  2. If a nonempty row starts with 1, begin with 0 to represent its empty white run.
  3. For a run longer than 35, emit z, then 0 for the opposite color, and continue the original run. Repeat while the remaining count exceeds 35, then emit its final count. For example, 36 white pixels encode as z01, and 70 white pixels encode as z0z.
  4. Encode an empty pixel row as an empty string. Add no other zero runs or trailing padding.

Decoding an encoded pixel row must recover exactly the same pixels, width, and row order. Re-encoding an existing packed row may normalize its spelling; it need not reproduce redundant zero runs. Run-length encoding does not guarantee a shorter string for every bitmap.

Render the recovered glyph

A character lookup supplies its bitmap rows, as in the linked character-rendering exercise. Apply encode: to those rows, then render: to the resulting packed rows, or apply roundtrip: directly. The recovered display must match the original glyph, including background pixels. Process requested glyphs individually; this follow-up adds no word spacing, padding, clipping, kerning, inversion, or other image transformation.

What the interview report shared

The report describes looking up a character bitmap, rendering it, and then compressing and decompressing the lookup data while rendering the same letters. Its detailed outline was copied from an older report. The following reported bitmap illustrates the letter J:

000010
000010
000010
000010
000010
000010
100010
011100
000000
000000

The report also mentions a later manipulation that reuses codec code, without identifying its transformation or required result. This exercise covers the disclosed rendering and reversible-codec scope; it does not assign a rule to that unspecified phase.

Function

decodeRle(encodedRows: String[]) → String[]

Examples

Example 1

encodedRows = ["23", "1a", "b0"]return = ["00111", "01111111111", "00000000000"]

23 becomes two white pixels followed by three black pixels. In 1a, a represents a run of length 10. In b0, b represents eleven white pixels and the final zero-length black run adds nothing.

Example 2

encodedRows = ["05", "02", "00"]return = ["11111", "11", ""]

Each row begins with a white run. A zero-length run adds no pixels, but the state still changes before the next run. Therefore 05 produces five black pixels, 02 produces two black pixels, and 00 produces an empty row.

Example 3

encodedRows = ["a2", "3c2"]return = ["000000000011", "00011111111111100"]

The letter a represents length 10, and c represents length 12. Thus a2 is ten white pixels followed by two black pixels, while 3c2 is three white pixels, twelve black pixels, and two white pixels.

Example 4

encodedRows = ["encode:00111", "decode:23", "render:23", "roundtrip:00111"]return = ["23", "00111", "..###", "..###"]

Two white pixels followed by three black pixels have canonical encoding 23. The inverse produces 00111, and both rendering paths produce ..###.

Example 5

encodedRows = ["", "encode:", "decode:00", "render:05", "roundtrip:11111"]return = ["", "", "", "#####", "#####"]

The first three entries produce empty rows. Decoding 05 yields five black pixels, and encoding the five-pixel black row starts with an empty white run. Both display as #####.

Example 6

encodedRows = ["encode:000000000000000000000000000000000000", "encode:111111111111111111111111111111111111", "encode:0000000000000000000000000000000000000000000000000000000000000000000000"]return = ["z01", "0z01", "z0z"]

A run of length 36 splits into 35 pixels, a zero run of the opposite color, and one remaining pixel. A black-first row also needs its leading white zero. Exactly 70 white pixels need two chunks of 35 separated by a black zero.

Constraints

  • 0 <= encodedRows.length <= 100.
  • For an untagged entry, 0 <= encodedRows[i].length <= 100, and the row contains only 0-9 and a-z.
  • Rows are decoded independently, so their decoded widths may differ.
  • An untagged row, or the payload of decode: or render:, contains at most 100 run characters from the original alphabet. The original limits above apply to those payloads, not to their command prefixes.
  • The payload of encode: or roundtrip: is a binary row of length 0 through 99. Its canonical encoding has at most 100 run characters, so it fits the original decoder limit.
  • Every command prefix is exactly one of those listed; there are no malformed inputs.

More Stripe problems

See Stripe hiring insights
public String[] decodeRle(String[] encodedRows) {
  // write your code here
}
encodedRows["23", "1a", "b0"]
expected["00111", "01111111111", "00000000000"]
Checking account…