LeetCode 316: Remove Duplicate Letters Solution in Python – A Step-by-Step Guide

Imagine you’re given a string with repeated letters, and you need to craft the smallest possible unique-letter version—like a word game where order matters, and every letter gets one shot. That’s the puzzle of LeetCode 316: Remove Duplicate Letters, a hard-level problem that blends stack operations with greedy choices. Using Python, we’ll explore two solutions: the Best Solution, a stack-based greedy approach that’s efficient and clever, and an Alternative Solution, a recursive method for a different perspective. With detailed examples, clear code, and a friendly tone—especially for the stack breakdown—this guide will help you dedupe that string, whether you’re new to coding or sharpening your skills. Let’s dive into the letters and build the smallest unique sequence!

What Is LeetCode 316: Remove Duplicate Letters?

Section link icon

In LeetCode 316: Remove Duplicate Letters, you’re given a string s, and your task is to remove duplicate letters to create a new string where each letter appears exactly once, in the smallest lexicographical order possible while preserving the relative positions of letters. For example, "bcabc" becomes "abc"—removing extra b and c to get the smallest unique sequence. This problem tests your ability to balance greediness with order, sharing ties with LeetCode 402: Remove K Digits.

Problem Statement

  • Input: A string s of lowercase English letters.
  • Output: A string—smallest lexicographical order with no duplicates, using all unique letters from s.
  • Rules:
    • Each letter appears once.
    • Relative order of letters in original string is maintained.
    • Result must be lexicographically smallest.

Constraints

  • 1 <= s.length <= 10⁴
  • s contains only lowercase English letters.

Examples

  • Input: "bcabc"
    • Output: "abc"
  • Input: "cbacdcbc"
    • Output: "acdb"
  • Input: "leetcode"
    • Output: "letcod"

Understanding the Problem: Crafting the Smallest Unique String

Section link icon

To solve LeetCode 316: Remove Duplicate Letters in Python, we need to remove duplicates from s while ensuring every unique letter appears once, in the smallest possible order, respecting their original sequence. A naive approach—generating all unique subsequences and picking the smallest—is O(2^n), far too slow. Instead, we’ll use:

  • Best Solution (Stack-Based Greedy): O(n) time, O(1) space—fast and smart.
  • Alternative Solution (Recursive): O(n) time with multiple passes, O(n) space—clear but less efficient.

Let’s start with the stack-based solution, explained in a beginner-friendly way.

Best Solution: Stack-Based Greedy Approach

Section link icon

Why This Is the Best Solution

The stack-based greedy approach is the top choice for LeetCode 316 because it’s efficient—O(n) time, O(1) space (ignoring output)—and elegantly builds the result in one pass. It uses a stack to maintain the smallest lexicographical order, popping larger letters when smaller ones appear later, guided by letter counts. It’s like crafting a word puzzle live—intuitive and quick once you get it!

How It Works

Think of this as building the string step-by-step:

  • Step 1: Track Last Occurrences:
    • Record the last index of each letter in s.
  • Step 2: Build with a Stack:
    • For each letter:
      • Skip if already in stack.
      • Pop larger letters from stack if they appear later.
      • Push current letter.
  • Step 3: Why It Works:
    • Greedy choice ensures smallest order.
    • Last occurrence check preserves all letters.

It’s like stacking letters, keeping only the best!

Step-by-Step Example

Example: s = "cbacdcbc"

  • Last Occurrences: c:7, b:6, a:3, d:4
  • Stack Process:
    • c: Stack = [c]
    • b: b<c, (c="" 7),="" at="" c="" later="" pop="" stack="[b]</li">
    • a: a<b, (b="" 6),="" at="" b="" later="" pop="" stack="[a]</li">
    • c: Stack = [a,c]
    • d: Stack = [a,c,d]
    • c: Skip (in stack)
    • b: Stack = [a,c,d,b]
    • c: Skip
  • Result: "acdb"

Code with Detailed Line-by-Line Explanation

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        # Track last occurrence of each letter
        last_occurrence = {}
        for i, char in enumerate(s):
            last_occurrence[char] = i

        # Stack to build result
        stack = []
        # Track seen letters
        seen = set()

        # Process each character
        for i, char in enumerate(s):
            # Skip if already in stack
            if char in seen:
                continue
            # Pop larger chars if they appear later
            while stack and char < stack[-1] and i < last_occurrence[stack[-1]]:
                seen.remove(stack.pop())
            stack.append(char)
            seen.add(char)

        # Build result
        return ''.join(stack)
  • Lines 3-5: Map each letter to its last index.
  • Lines 8-9: Initialize stack and seen set.
  • Lines 12-19: Loop:
    • Skip duplicates.
    • Pop larger letters if safe (appear later).
    • Add current letter.
  • Line 21: Join stack to string.
  • Time Complexity: O(n)—one pass, stack ops O(1) amortized.
  • Space Complexity: O(1)—stack and set bounded by 26 letters.

This is like a letter-stacking pro—swift and sleek!

Alternative Solution: Recursive Approach

Section link icon

Why an Alternative Approach?

The recursive approach also solves it in O(n) time (with multiple passes), O(n) space, breaking the problem into smaller subproblems. It’s more intuitive for some, finding the smallest letter that can start the result, then recurring on the suffix. It’s like solving a word puzzle piece-by-piece—clear but less efficient!

How It Works

Divide and conquer:

  • Step 1: Find smallest letter that appears last among duplicates.
  • Step 2: Recur on suffix after its first occurrence.
  • Step 3: Build result by prepending.

Step-by-Step Example

Example: s = "bcabc"

  • Pass 1: Smallest = a, First at 2, Result = "a" + rec("bc")
  • Pass 2: Smallest = b, First at 0, Result = "b" + rec("c")
  • Pass 3: Smallest = c, Result = "c"
  • Combine: "abc"

Code for Recursive Approach

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        if not s:
            return ""

        # Count occurrences
        count = {}
        for char in s:
            count[char] = count.get(char, 0) + 1

        # Find smallest letter that can be first
        pos = 0
        for i in range(len(s)):
            if s[i] < s[pos]:
                pos = i
            count[s[i]] -= 1
            if count[s[i]] == 0:
                break

        # Recur on suffix after first occurrence of smallest
        suffix = s[pos+1:].replace(s[pos], "")
        return s[pos] + self.removeDuplicateLetters(suffix)
  • Time Complexity: O(n)—multiple passes, but O(n) total work.
  • Space Complexity: O(n)—recursion stack and string ops.

It’s a recursive word crafter!

Comparing the Two Solutions

Section link icon
  • Stack-Based (Best):
    • Pros: O(n) time, O(1) space, one pass.
    • Cons: Greedy logic trickier.
  • Recursive (Alternative):
    • Pros: O(n) time, O(n) space, intuitive breakdown.
    • Cons: More memory, slower.

Stack wins for efficiency.

Additional Examples and Edge Cases

Section link icon
  • "a": "a".
  • "aaa": "a".
  • "zxy": "xyz".

Both handle these perfectly.

Complexity Breakdown

Section link icon
  • Stack-Based: Time O(n), Space O(1).
  • Recursive: Time O(n), Space O(n).

Stack is leaner and faster.

Key Takeaways

Section link icon
  • Stack-Based: Greedy stacking—brilliant!
  • Recursive: Divide and conquer—clear!
  • Python: Stacks and dicts shine—see [Python Basics](/python/basics).
  • Order: Lexicography meets greediness.

Final Thoughts: Dedupe with Style

Section link icon

LeetCode 316: Remove Duplicate Letters in Python is a string manipulation masterpiece. The stack-based solution offers speed and elegance, while recursion provides a thoughtful alternative. Want more string challenges? Try LeetCode 402: Remove K Digits or LeetCode 1081: Smallest Subsequence of Distinct Characters. Ready to dedupe? Head to Solve LeetCode 316 on LeetCode and craft that smallest string today!