← Questions

Match applicant skills and versions to a job's requirements

0
StripeCoding

An applicant tracking system screens candidates by the skills they list. Each applicant gives one comma-separated string of skills, strongest first. A job posting gives a comma-separated string of required skills.

A skill token is a name with an optional version after a hyphen, such as Rust-1.70, SQL or Go-Lang.

Part 1: parse and match

Implement is_qualified(applicant: str, required: str) -> bool. It returns True when the applicant lists every required skill.

  • Trim the whitespace around each token and ignore empty tokens.
  • Compare skill names case-insensitively.
  • A token has a version only when the part after its last hyphen is numeric, made of digits and dots (3, 1.70, 2.0.1). Go-Lang is the name go-lang with no version.
  • If an applicant lists a skill twice, the first copy counts.

Part 2: versions

Now the versions count.

  • A required skill with no version accepts any version of that skill.
  • A required skill with a version needs an applicant version at least that high. Compare versions numerically, part by part: 1.70 > 1.9, and 3.0 == 3.
  • An applicant who lists a skill without a version does not meet a versioned requirement for that skill.

Part 3: rank applicants

Implement rank_applicants(applicants: dict[str, str], required: str, preferred: str = "") -> list[str]. It returns the names of the qualified applicants, best first:

  1. More preferred skills met first. Preferred skills follow the same version rules.
  2. Then the smaller sum of the 0-based positions where the required skills appear in the applicant's list.
  3. Then the name, alphabetically.

Examples

is_qualified("Rust-1.70, Go-Lang, SQL", "sql, go-lang")  -> True
is_qualified("Rust-1.9", "Rust-1.70")                    -> False   # 9 < 70
is_qualified("Rust", "Rust-1")                           -> False
apps = {
  "ana": "SQL, Kotlin-1.9, Rust-1.75",
  "bo":  "Rust-1.80, SQL",
  "cy":  "Rust-1.60, SQL, Kotlin-2",
  "di":  "Kotlin-2, Rust-1.72, SQL",
}
rank_applicants(apps, "Rust-1.70, SQL")              -> ["bo", "ana", "di"]
rank_applicants(apps, "Rust-1.70, SQL", "Kotlin-2")  -> ["di", "bo", "ana"]

cy is not qualified because Rust 1.60 is below 1.70.

Constraints

  • Up to 10,000 applicants. Each lists up to 100 skills, and a job has up to 50 required skills.
  • State the time and space complexity of each function.

Clarifying questions

  • In Part 1, does a required skill with a version (Rust-1.70) still match by name only, as long as the applicant lists Rust?
  • Can the required string itself list a skill twice, perhaps with two versions?
  • Is 1.70 read as the parts [1, 70], so trailing zeros are significant there but 3.0 == 3 because missing parts are zero?
  • Are hyphens ever used before a non-numeric suffix with a version after it, like Python-3-beta?
  • In Part 3, do preferred skills that are also required count toward both rules?

What a strong answer covers

  • One parser shared by every part: trim, skip empty tokens, split on the last hyphen only when the tail is digits and dots, lower-case the name, and turn the version into a tuple of integers.
  • Turns the applicant list into a dict from name to (version, position), keeping the first copy, so each requirement is one lookup. That is O(a + r) per check.
  • Compares versions as integer tuples padded with zeros, so 1.70 > 1.9 and 3.0 == 3, and treats "no version" as failing a versioned requirement.
  • Ranks with one sort key (-preferred_met, position_sum, name) over the qualified applicants. That is O(A * (a + r + p) + A log A).
  • Tests: the examples, Go-Lang with no version, a duplicate skill, whitespace and empty tokens, version ties like 3 against 3.0.0, and ties broken by name.

Follow-ups

  • Version ranges and caps (Python>=3.8,<4).
  • Skill aliases (JS and JavaScript, Postgres and PostgreSQL).
  • Score partial matches so near-qualified applicants are shown too.
  • Screen millions of applicants against many jobs: build an index from skill to applicants.
Write and test your solution herePython in your browser, the question's tests level by level, every submission kept for you.Sign in to start coding