I finished 3rd out of about 6,000 competitors on a HackerRank challenge in the AI -> Statistics and Machine Learning track, and the final version of my solution came together in roughly 30 minutes.
If you enjoy problem solving in this space, welcome - this write-up is for you.
Problem link: Matching Questions with their Answers
If you are interested in statistics/machine-learning style reasoning problems, this one is a great example: it looks like simple text matching, but it really tests scoring, disambiguation, and robust decision-making under noisy input.
What looked easy on paper turned out to be surprisingly tricky in practice: five questions, five shuffled answers, and one paragraph where multiple answers can seem valid. The difference-maker was not a giant algorithm - it was combining a few solid ideas quickly and cleanly.
The Problem
Input has:
- one paragraph,
- five factual questions,
- five candidate answers in random order.
Output must be the correct answer for each question, in question order.
All valid outputs must be exact substrings from the provided paragraph, which is where the matching strategy becomes interesting.
What I Did Differently
1) I used context scoring, not plain keyword overlap
A naive solution counts common words and guesses. That breaks when two options share similar wording.
So I scored each question-answer pair using:
- keyword overlap in the same sentence,
- keyword overlap in a local window around the answer,
- distance from question keywords to the answer location in the paragraph.
This was the first big jump in accuracy.
def question_keywords(question):
return [t for t in tokenize(question) if t not in STOPWORDS]
def build_keyword_positions(paragraph_lower):
positions = {}
for m in re.finditer(r"[a-z0-9']+", paragraph_lower):
tok = m.group(0)
positions.setdefault(tok, []).append(m.start())
return positions
2) I added simple intent rules for common question types
I noticed recurring patterns and gave them light heuristic boosts:
-
how far,how long,height-> prefer numeric answers, -
highest point-> prefer a named entity over a measurement, -
lowest point-> prefer a measurement, -
called/known as-> prefer label-like text instead of numeric values.
Small rules, big effect on tie-breaks.
if "height" in ql or "how far" in ql or "how long" in ql:
score += 3.0 if has_digit else -2.5
if ("called" in ql or "known as" in ql) and has_digit:
score -= 2.0
if "which is the highest point" in ql or "highest point in" in ql:
score += -2.2 if has_digit else 1.5
if "lowest point" in ql and has_digit:
score += 2.0
3) I anchored "What is X?" questions to the actual entity
Questions like What is INSEAD? and What is ESIGETEL? can be confused if both answers are descriptive.
So I explicitly extracted the target entity and boosted candidates near that mention:
- extracts the target entity (
INSEAD,ESIGETEL), - boosts answers near the entity mention in the paragraph,
- adds extra score if both appear in the same sentence.
That cut down wrong swaps between definition-style answers.
def extract_target_entity(question):
m = re.search(r"\b(?:what|who|where|when)\s+is\s+(.+?)\s*\?\s*$", question, flags=re.I)
if not m:
return ""
return m.group(1).strip(" .")
# inside scoring
if ent_l and ent_pos != -1:
ent_center = ent_pos + len(ent_l) // 2
dist = abs(ent_center - center)
score += 4.0 / (1.0 + dist / 80.0)
4) I used exact assignment instead of greedy matching
Greedy matching can lock into a bad early pick. Since there are only five answers, I just checked all permutations (5! = 120) and selected the max total score.
For this problem size, brute force is clean, exact, and very fast.
best_perm = None
best_score = -10**18
for perm in itertools.permutations(range(n)):
total = 0.0
for i, j in enumerate(perm):
total += score_matrix[i][j]
if total > best_score:
best_score = total
best_perm = perm
5) I hardened the solution for real test noise
Two practical fixes helped with stubborn edge cases:
- normalize common mojibake patterns before matching,
- score across all occurrences of an answer in the paragraph (not just the first one).
These details mattered more than expected on hidden tests.
def normalize_text(text):
fixed = text
if any(marker in fixed for marker in ("\u00C2", "\u00C3", "\u00EF\u00BF\u00BD", "\uFFFD")):
for enc in ("latin-1", "cp1252"):
try:
fixed = fixed.encode(enc).decode("utf-8")
break
except Exception:
pass
return fixed.replace("\ufffd", "")
Why This Ranked High enough
This rank was not about one clever hack. It came from combining:
- semantic/context scoring,
- targeted heuristics,
- exact combinational optimization,
- defensive text normalization.
That gave me both visible-test accuracy and hidden-test stability, which is exactly what leaderboard positions reward.
Final Thoughts
Top-3 out of 6,000 in about 30 minutes was a strong reminder: in competitive coding, practical engineering choices often matter as much as core algorithm logic.
I did not overcomplicate the approach. I kept it understandable, added targeted scoring logic, and made sure edge cases would not break it. That balance is what carried this solution to the top.
If I get more time, I will keep competing in this track and share more breakdowns like this one, so feel free to follow for upcoming problem-solving articles.

Top comments (0)