Katkat

Implement Text Layout and Query Parsing

AirbnbSoftware Engineer · Technical Screen

Last updated

Implement URL query parameter extraction and a greedy text line-wrapper that enforces maximum line length and prevents orphan words on the final line.

Problem Statement

Airbnb listing titles and descriptions must be rendered dynamically across various web and mobile layouts. You are tasked with implementing a function that extracts layout parameters from a URL request and formats the display text into wrapped lines.

Your task is to write a function format_query_text(url: str) -> list[str] that performs two operations:

  1. URL Query Parsing:

    • Extract the query parameters following the ? character in the url.
    • Key-value pairs are separated by &, and keys are separated from values by =. If a key has no value or = is omitted, treat its value as an empty string.
    • Decode spaces in values: replace occurrences of + and %20 with a single space ' '.
    • Extract text (the text string to wrap) and width (an integer maximum line width). If width is missing or not a valid positive integer, default to 20. If text is missing or empty, return an empty list [].
  2. Text Layout & Wrapping:

    • Split text into words by whitespace.
    • Pack words greedily into lines such that each line contains as many words as possible without its total character count (including single spaces between words) exceeding width.
    • Any trailing punctuation attached to a word (e.g., "cabin," or "view!") is treated as part of that word.
    • Orphan Prevention: If the resulting layout produces more than one line and the final line contains only a single word, rebalance the last two lines if possible. Specifically, move the last word from the second-to-last line to the beginning of the final line, provided that:
      • The second-to-last line had at least 2 words prior to the move, and
      • The new final line does not exceed width.
      • If moving the word would exceed width, leave the layout as-is.

Interface

def format_query_text(url: str) -> list[str]:
    pass

Input & Output

  • Input: url: str - a URL string possibly containing query parameters.
  • Output: list[str] - a list of lines representing the wrapped text.

Constraints

  • 1 <= len(url) <= 1000
  • 5 <= width <= 100
  • You may assume every individual word has a length less than or equal to width.
  • No built-in URL parsing libraries (such as urllib.parse) should be used; implement parsing manually.

Examples

Example 1

url = "https://airbnb.com/search?text=Cozy+cabin+in+the+woods&width=10"
output = format_query_text(url)
# Output: ["Cozy cabin", "in", "the woods"]

Explanation:

  1. Parameters extracted: text = "Cozy cabin in the woods", width = 10.
  2. Greedy wrapping gives: ["Cozy cabin", "in the", "woods"].
  3. The last line has only 1 word ("woods"). The preceding line has 2 words ("in the"). Moving "the" down creates "the woods" (length 9 <= 10), leaving "in" on the second-to-last line.

Example 2

url = "https://airbnb.com/rooms?text=Quiet%20loft&width=20"
output = format_query_text(url)
# Output: ["Quiet loft"]

Explanation:

  1. Parameters: text = "Quiet loft", width = 20.
  2. Both words fit within width 20 on a single line.

Hints

Hint 1

Isolate query parsing first by splitting at '?' and '&', and remember to replace both '+' and '%20' with standard space characters.

Hint 2

Perform a standard greedy packing pass using a list of words per line before considering line-balancing adjustments.

Hint 3

Check the orphan condition only on the final line: inspect whether len(lines[-1]) == 1 and len(lines[-2]) >= 2, then calculate if moving the word satisfies the width constraint.

Follow-up questions

  • How would you handle full percent-decoding (e.g., %2C for commas or %2F for slashes) without external libraries?
  • How could this layout algorithm be modified to support full justification (evenly distributing spaces between words)?
  • If orphan prevention was required for all lines (preventing any line from having fewer than two words, where possible), how would you structure the dynamic programming or search approach?