The Scramble Check

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
L3

Problem

Every character counts exactly as written, capitals, spaces and punctuation included, and each one has to appear the same number of times in both strings. An on-call engineer cleaning up log tokens wants to know whether s2 is just s1 with its characters shuffled.

Same letters, different order - are these two strings secret twins?

Example 1

Input:

s1 = "listen", s2 = "silent"

Output:

true

Example 2

Input:

s1 = "hello", s2 = "world"

Output:

false

Worked solution and explanation

What this really is

This is a multiset equality check dressed up as log hygiene. Everyone reaches for counting; what separates candidates is knowing what each shortcut cannot see. Compare sets and 'aabb' passes as 'abbb', because both hold just a and b. Lowercase first and 'Listen' matches 'silent', which the engineer never asked for. And spend one string's counts against the other without checking lengths, and 'error' passes as 'eror': a shorter string can never overdraw a longer one's budget, so the leftovers go unnoticed.

Building it

Step 1: Guard on length first

A shuffle neither adds nor drops a character, so unequal lengths end it right there. In this shape the guard is not a speed trick: the spend-down loop below only catches s2 asking for a character s1 ran out of, never s1 holding characters s2 didn't use.

Step 2: Count s1 into remaining

Walk s1 once and build remaining, how many of each character are available. Capitals, spaces and dashes are keys like any other; nothing is normalized.

Step 3: Spend the counts against s2

Walk s2 and decrement. If a character's count is already zero, or it never appeared, s2 has more of it than s1: return False on the spot. Reach the end and every count is back to zero, because the lengths matched and nothing went negative.

One budget, spent down
def check_string_permutation(s1, s2):
    if len(s1) != len(s2):
        return False
    remaining = {}
    for ch in s1:
        if ch in remaining:
            remaining[ch] += 1
        else:
            remaining[ch] = 1
    for ch in s2:
        if remaining.get(ch, 0) == 0:
            return False
        remaining[ch] -= 1
    return True
Two maps compared
Count both strings and compare the dicts with ==. Dict equality sees leftovers on either side, so the length check is only a shortcut here, and you hold two maps until the very end.
One map spent down
Count s1, decrement through s2. Half the memory and it exits on the first overdraw, but it only looks one way, so the length guard is what makes it correct.

Common follow-up questions