C# Program to Remove Duplicates from String
HashSet to track seen characters and build a new string with only unique characters, like this: var seen = new HashSet(); var result = new string(input.Where(c => seen.Add(c)).ToArray()); Examples
How to Think About It
Algorithm
Code
using System; using System.Collections.Generic; using System.Text; class Program { static void Main() { string input = "programming"; string output = RemoveDuplicates(input); Console.WriteLine(output); } static string RemoveDuplicates(string input) { HashSet<char> seen = new HashSet<char>(); StringBuilder result = new StringBuilder(); foreach (char c in input) { if (seen.Add(c)) { result.Append(c); } } return result.ToString(); } }
Dry Run
Let's trace the input "programming" through the code
Initialize
input = "programming", seen = {}, result = ""
Process 'p'
seen = {'p'}, result = "p"
Process 'r'
seen = {'p','r'}, result = "pr"
Process 'o'
seen = {'p','r','o'}, result = "pro"
Process 'g'
seen = {'p','r','o','g'}, result = "prog"
Process 'r' again
already in seen, skip
Process 'a'
seen = {'p','r','o','g','a'}, result = "proga"
Process 'm'
seen = {'p','r','o','g','a','m'}, result = "progam"
Process 'm' again
already in seen, skip
Process 'i'
seen = {'p','r','o','g','a','m','i'}, result = "progami"
Process 'n'
seen = {'p','r','o','g','a','m','i','n'}, result = "progamin"
Process 'g' again
already in seen, skip
| Character Processed | Seen Set | Result String |
|---|---|---|
| p | {p} | p |
| r | {p,r} | pr |
| o | {p,r,o} | pro |
| g | {p,r,o,g} | prog |
| r | {p,r,o,g} | prog |
| a | {p,r,o,g,a} | proga |
| m | {p,r,o,g,a,m} | progam |
| m | {p,r,o,g,a,m} | progam |
| i | {p,r,o,g,a,m,i} | progami |
| n | {p,r,o,g,a,m,i,n} | progamin |
| g | {p,r,o,g,a,m,i,n} | progamin |
Why This Works
Step 1: Use HashSet to Track Characters
The HashSet stores characters already seen, so we can quickly check if a character is a duplicate.
Step 2: Build Result with Unique Characters
We add characters to the result only if they are not in the set, ensuring no duplicates appear.
Step 3: Return the Clean String
Finally, we convert the collected characters back to a string and return it as the result without duplicates.
Alternative Approaches
using System; using System.Linq; class Program { static void Main() { string input = "programming"; string output = new string(input.Distinct().ToArray()); Console.WriteLine(output); } }
using System; using System.Text; class Program { static void Main() { string input = "programming"; StringBuilder result = new StringBuilder(); foreach (char c in input) { if (!result.ToString().Contains(c)) { result.Append(c); } } Console.WriteLine(result.ToString()); } }
Complexity: O(n) time, O(n) space
Time Complexity
The program loops through each character once, and HashSet operations like Add are O(1) on average, so total time is O(n) where n is string length.
Space Complexity
Extra space is used for the HashSet and the result string builder, both proportional to the number of unique characters, up to O(n).
Which Approach is Fastest?
Using HashSet is fastest for large strings due to O(1) lookups, while LINQ Distinct is concise and preserves order, and string Contains checks are slower.
| Approach | Time | Space | Best For |
|---|---|---|---|
| HashSet with StringBuilder | O(n) | O(n) | Preserving order efficiently |
| LINQ Distinct | O(n) | O(n) | Concise code, preserves order |
| StringBuilder with Contains | O(n²) | O(n) | Simple code, small strings only |