githubEdit

29. Stream First Non-repeating

βœ… GFG solution to the Stream First Non-repeating problem: efficiently find the first non-repeating character at each position using queue-based stream processing. πŸš€

The problem can be found at the following link: πŸ”— Question Linkarrow-up-right

🧩 Problem Description

Given a string s consisting of only lowercase alphabets, for each index i in the string (0 ≀ i < n), find the first non-repeating character in the prefix s[0..i]. If no such character exists, use '#'.

This problem simulates processing a stream of characters where at each step, we need to determine the first character that has appeared exactly once so far.

πŸ“˜ Examples

Example 1

Input: s = "aabc"
Output: "a#bb"
Explanation: 
At i=0 ("a"): First non-repeating character is 'a'.
At i=1 ("aa"): No non-repeating character, so '#'.
At i=2 ("aab"): First non-repeating character is 'b'.
At i=3 ("aabc"): Non-repeating characters are 'b' and 'c'; 'b' appeared first, so 'b'.

Example 2

Input: s = "bb"
Output: "b#"
Explanation: 
At i=0 ("b"): First non-repeating character is 'b'.
At i=1 ("bb"): No non-repeating character, so '#'.

πŸ”’ Constraints

  • $1 \le \text{s.size()} \le 10^5$

βœ… My Approach

The optimal approach uses a Queue with Frequency Array to efficiently track non-repeating characters in the order they appear:

Queue-Based Stream Processing

  1. Initialize Data Structures:

    • Use a frequency array freq[26] to count occurrences of each character.

    • Maintain a queue to store characters in the order they first appear.

    • Build result string incrementally.

  2. Process Each Character:

    • For each character c in the stream:

      • Increment its frequency in the array.

      • Add the character to the queue.

  3. Remove Repeating Characters:

    • While the queue is not empty and the front character has frequency > 1:

      • Remove it from the queue (it's no longer a candidate).

  4. Determine First Non-Repeating:

    • If queue is empty: append '#' to result.

    • Otherwise: append the front of the queue (first non-repeating character).

  5. Build Result:

    • Repeat for all characters and return the final result string.

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n), where n is the length of the string. Each character is added to the queue once and removed at most once, resulting in linear time complexity. The frequency update and queue operations are O(1) per character.

  • Expected Auxiliary Space Complexity: O(26) = O(1), as we use a fixed-size frequency array of 26 elements for lowercase letters and a queue that stores at most 26 distinct characters at any time, resulting in constant auxiliary space.

πŸ§‘β€πŸ’» Code (C++)

chevron-right⚑ View Alternative Approaches with Code and Analysishashtag

πŸ“Š 2️⃣ Doubly Linked List with Hash Map

πŸ’‘ Algorithm Steps:

  1. Maintain a doubly linked list to track non-repeating characters in order.

  2. Use a hash map to store frequency and node reference for each character.

  3. For each character, update frequency and remove from list if frequency becomes 2.

  4. The head of the list always points to the first non-repeating character.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) - Each character processed once with O(1) operations

  • Auxiliary Space: πŸ’Ύ O(26) - Constant space for at most 26 lowercase letters

βœ… Why This Approach?

  • Efficient removal of repeating characters

  • Maintains insertion order automatically

  • Optimal for stream processing scenarios

πŸ“Š 3️⃣ Two-Pass Array Approach

πŸ’‘ Algorithm Steps:

  1. First pass: count frequency of each character in the string.

  2. Second pass: for each position, scan all 26 characters to find earliest non-repeating.

  3. Track first occurrence position for each character during initial scan.

  4. Build result by finding minimum position character with frequency 1 at each step.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(26*n) = O(n) - Constant factor of 26 for each position

  • Auxiliary Space: πŸ’Ύ O(1) - Fixed size arrays only

βœ… Why This Approach?

  • No dynamic data structures needed

  • Simple array-based implementation

  • Predictable memory usage pattern

πŸ“Š 4️⃣ Deque-Based Sliding Window

πŸ’‘ Algorithm Steps:

  1. Use deque to maintain potential non-repeating characters in order.

  2. Track frequency array to check repetition status.

  3. For each new character, add to deque and update frequency.

  4. Remove characters from front of deque if they have become repeating.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) - Each character enters and leaves deque at most once

  • Auxiliary Space: πŸ’Ύ O(26) - Constant space for lowercase letters

βœ… Why This Approach?

  • Clean deque-based implementation

  • Natural FIFO behavior for ordering

  • Efficient front and back operations

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

🎯 Queue-Based

🟒 O(n)

🟒 O(1)

πŸš€ Simple and optimal

πŸ’‘ Requires queue understanding

πŸ”— Doubly Linked List

🟒 O(n)

🟒 O(1)

⚑ Fast removal operations

πŸ”§ More complex implementation

πŸ“Š Two-Pass Array

🟑 O(26*n)

🟒 O(1)

πŸ“– Easy to understand

🐌 Constant factor overhead

πŸͺŸ Deque-Based

🟒 O(n)

🟒 O(1)

🎯 Natural ordering

πŸ’Ύ Slightly more space than queue

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

πŸ… Optimal performance needed

πŸ₯‡ Queue-Based

β˜…β˜…β˜…β˜…β˜…

πŸ“– Simplicity priority

πŸ₯ˆ Deque-Based

β˜…β˜…β˜…β˜…β˜†

πŸ”§ No STL containers

πŸ₯‰ Two-Pass Array

β˜…β˜…β˜…β˜†β˜†

🎯 Interview/Stream processing

πŸ… Doubly Linked List

β˜…β˜…β˜…β˜…β˜…

β˜• Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?arrow-up-right. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated