Skip to content
← All posts

License Key Formatting: String Manipulation from the Right

5 min read
leetcodeproblemeasystrings

LeetCode 482, License Key Formatting, gives you a string s representing a license key and an integer k. The key contains alphanumeric characters and dashes. Your job is to reformat it so that every group (except possibly the first) has exactly k characters, all letters are uppercase, and groups are separated by dashes.

For example, given s = "5F3Z-2e-9-w" and k = 4, the answer is "5F3Z-2E9W".

Input (k=4)5F3Z-2e-9-wstrip dashesDashes removed5F3Z2e9wuppercaseUppercased5F3Z2E9Wgroup from right (k=4)Result5F3Z-2E9W4 chars4 chars
"5F3Z-2e-9-w" with k=4 becomes "5F3Z-2E9W". Strip dashes, uppercase everything, then regroup from the right.

Why this problem matters

License Key Formatting is a practical string manipulation exercise. It combines three operations you will see again and again: filtering out unwanted characters, case conversion, and chunking a string into fixed-size groups. The twist here is that grouping happens from the right, which means the first group can be shorter than k. That one detail is what separates this problem from a simple split-and-join.

The same right-to-left grouping logic appears whenever you format numbers with commas (like 1,000,000) or break serial numbers into blocks. Once you internalize the pattern, you can adapt it to any formatting problem that works backward from the end.

The approach

The strategy has three clean phases:

  1. Strip all dashes and convert the entire string to uppercase. This gives you a flat sequence of characters with no formatting noise.
  2. Figure out the first group size. The total character count modulo k tells you how many characters go in the first group. If the remainder is zero, every group is full.
  3. Build the result by walking through the cleaned string and inserting a dash every k characters after the first group.

You can simplify this even further. Instead of computing the remainder separately, just build the string from the cleaned characters and insert dashes at the right positions. The key observation is that if you process the characters in order and track your position, you can insert a dash whenever you have placed k characters in the current group.

An even cleaner approach: reverse the cleaned string, chunk it into groups of k, reverse each chunk, then reverse the whole list. But the most readable version is the one that walks forward and uses modular arithmetic.

The solution

def licenseKeyFormatting(s: str, k: int) -> str:
    cleaned = s.replace("-", "").upper()

    first_group_size = len(cleaned) % k
    parts = []

    if first_group_size > 0:
        parts.append(cleaned[:first_group_size])

    for i in range(first_group_size, len(cleaned), k):
        parts.append(cleaned[i:i + k])

    return "-".join(parts)

cleaned = s.replace("-", "").upper(). This is the preprocessing step. You remove every dash and convert all letters to uppercase in one shot. Now you have a flat string of only alphanumeric characters.

first_group_size = len(cleaned) % k. This computes how many characters belong in the first group. If the total length is evenly divisible by k, the first group size is 0 and you skip it.

parts.append(cleaned[:first_group_size]). If there is a partial first group, you slice it off and add it to the parts list.

for i in range(first_group_size, len(cleaned), k). Starting right after the first group, you slice off chunks of exactly k characters until you run out of string.

return "-".join(parts). Join all the groups with dashes. Done.

Visual walkthrough

Trace through s = "5F3Z-2e-9-w" with k = 4. Watch how the string gets cleaned, then split into groups from the right.

Step 1: Start with the original key

5F3Z-2e-9-w

The input is "5F3Z-2e-9-w" with k = 4. We need to reformat it into groups of 4, uppercased, with dashes as separators.

Step 2: Remove all dashes

5F3Z2e9w

Dashes are purely cosmetic. Strip them out to get the raw characters: "5F3Z2e9w" (length 8).

Step 3: Convert to uppercase

5F3Z2E9W

Every letter becomes uppercase: "e" turns into "E", "w" turns into "W". Digits stay the same.

Step 4: Group from the right with k = 4

5F3Z-2E9Wgroup 1group 2

8 characters split into groups of 4 from the right: [5F3Z] [2E9W]. Since 8 divides evenly by 4, the first group is also full. Insert dashes between groups.

Step 5: Final result

5F3Z-2E9W

Join the groups with dashes to get "5F3Z-2E9W". If the total length were not evenly divisible by k, the first group would simply be shorter.

The cleaned string "5F3Z2E9W" has 8 characters. Since 8 % 4 = 0, the first group is a full group of 4. Both groups end up with exactly k characters. If the cleaned string had been 6 characters instead, the first group would have been 2 and the second group 4.

Complexity analysis

MetricValue
TimeO(n), where n is the length of the input string
SpaceO(n), for the cleaned string and the result

The replace call scans every character once. The upper call scans every character once. The slicing loop visits every character once. Each operation is O(n), and they do not nest, so the total is O(n). The cleaned string and parts list together use O(n) space.

Building blocks

This problem decomposes into two reusable ideas.

String cleaning (filter and transform)

Removing unwanted characters and normalizing case is a pattern that appears in many string problems. Valid Palindrome asks you to strip non-alphanumeric characters. Group Anagrams asks you to sort characters. The first step is always the same: reduce the input to its essential form before doing any real work.

Right-to-left grouping with modular arithmetic

When you need to split a sequence into fixed-size groups starting from the right, the remainder (len % k) tells you the size of the leftover first group. This is the same idea behind formatting large numbers with comma separators. The pattern is: handle the partial first group, then iterate in steps of k for the rest.

Edge cases

First group is shorter than k. If len(cleaned) % k is not zero, the first group has fewer than k characters. For example, s = "2-5g-3-J" with k = 2 produces "2-5G-3J". The first group is just "2".

All dashes. If the input is something like "---", the cleaned string is empty. You return an empty string.

Single character. s = "a" with any k produces "A". One character, one group.

Already correctly formatted. If the input happens to already be in the right format, you still strip and rebuild. The algorithm does not try to detect this case, and it does not need to.

k equals the full length. If k is equal to or larger than the number of characters, the entire string becomes one group with no dashes.

From understanding to recall

The logic here is simple enough to read and understand in a few minutes. But reproducing it from scratch in an interview means remembering the three-phase approach (clean, compute first group size, slice in steps of k) and getting the modular arithmetic right. The most common mistake is grouping from the left instead of the right, which produces the wrong first group size.

Practice writing the solution on a blank screen. Test it against a case where the first group is shorter, a case where it divides evenly, and the empty-after-cleaning edge case. Once you can produce the code without hesitation, space out your reviews so the pattern sticks.

Related posts

  • String Compression - Another string transformation problem where you process characters in groups and build a modified output.
  • Reverse String - The core two-pointer reversal pattern, useful when you want to think about strings from the right side.
  • Add Strings - Digit-by-digit processing from right to left, the same directional thinking that applies to license key grouping.