# The First Stranger

> In a crowd, the unique ones stand out first.

Canonical URL: <https://datadriven.io/problems/the_first_stranger>

Domain: Python · Difficulty: easy · Seniority: L3

## Problem

Given a string, return the first (leftmost) character that appears exactly once. Return an empty string if no such character exists.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests **frequency counting combined with order-preserving search**, a classic string problem. It probes two-pass thinking: first count all characters, then find the first with count 1.

---

### Break down the requirements

#### Step 1: Count character frequencies

First pass: build a frequency dict.

#### Step 2: Find the first character with count 1

Second pass: iterate the original string and return the first character whose count is 1.

---

### The solution

**Two-pass frequency then search**

```python
def first_unique_char(s: str) -> str:
    freq = {}
    for ch in s:
        if ch in freq:
            freq[ch] += 1
        else:
            freq[ch] = 1
    for ch in s:
        if freq[ch] == 1:
            return ch
    return ""
```

> **Time and Space Complexity**
>
> **Time:** O(n) for two passes through the string.
> 
> **Space:** O(k) where k is the number of unique characters.

> **Interviewers Watch For**
>
> The two-pass approach. A single-pass solution using `OrderedDict` is possible but harder to implement correctly.

> **Common Pitfall**
>
> Iterating through the dict instead of the original string for the second pass. Dict iteration order matches insertion order (Python 3.7+), but iterating the string is clearer and more explicit about finding the first non-repeater.

---

## Common follow-up questions

- How would you solve this with a single pass? _(Tests using an `OrderedDict` that tracks counts and removes keys when count exceeds 1.)_
- What if the string is a stream and you cannot revisit characters? _(Tests maintaining insertion-ordered tracking with live filtering.)_
- What if the comparison should be case-insensitive? _(Tests normalizing with `.lower()` while preserving the original character for return.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/the_first_stranger)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.