Check Unique Characters
Java coding interview problem for Character Problems: Check Unique Characters.
Checking whether a string contains all unique characters is one of the most frequently asked Java String interview questions.
Although it appears simple, this problem tests your understanding of:
- String Traversal
- HashSet
- Arrays
- Bit Manipulation
- Time Complexity
- Space Complexity
- Character Encoding
This question is commonly asked by companies like Amazon, Microsoft, Google, Oracle, IBM, Adobe, Walmart, and many product-based companies.
Mastering this problem also helps solve advanced interview questions such as:
- Remove Duplicate Characters
- First Non-Repeating Character
- Character Frequency
- Detect Duplicate Characters
- Longest Substring Without Repeating Characters
Problem Statement
Given a string,
determine whether every character appears exactly once.
Return
- true if all characters are unique.
- false if any character repeats.
Example 1
Input
abcdef
Output
true
Explanation
a b c d e f
All characters are unique.
Example 2
Input
hello
Output
false
Explanation
l appears twice.
Example 3
Input
Java
Output
false
Explanation
a appears twice.
Example 4
Input
12345
Output
true
Example 5
Input
abca
Output
false
What are Unique Characters?
A string contains unique characters if no character is repeated.
Example
Unique
Python
Characters
P
y
t
h
o
n
Every character occurs exactly once.
Not Unique
banana
Frequency
b → 1
a → 3
n → 2
Repeated characters exist.
Why is this Question Asked in Interviews?
Interviewers use this question to evaluate your understanding of:
- HashSet
- Hashing
- Arrays
- Bit Manipulation
- String Traversal
- Character Encoding
- Time Complexity
- Space Complexity
This problem has multiple optimal solutions, making it ideal for interview discussions.
Real-World Applications
Checking unique characters is useful in many real-world applications.
Username Validation
Ensure usernames contain unique identifiers.
Example
venu123
Password Analysis
Detect repeated characters in passwords.
Example
Pass@123
Data Validation
Ensure IDs contain no duplicate symbols.
License Key Verification
Example
ABCD-1234
Verify uniqueness if required.
DNA Sequence Analysis
Identify repeated nucleotide patterns.
Cryptography
Validate uniqueness of generated keys or tokens.
Understanding Character Uniqueness
Input
apple
Read one character at a time.
Read
a
Store
Seen = {a}
Read
p
Store
Seen = {a,p}
Read
p
Already exists.
Duplicate found.
Return
false
No need to continue.
ASCII Visualization
Input
code
c
↓
Not Seen
↓
Store
o
↓
Not Seen
↓
Store
d
↓
Not Seen
↓
Store
e
↓
Not Seen
↓
Store
Result
Unique
Input
hello
h
↓
Store
e
↓
Store
l
↓
Store
l
↓
Already Present
↓
Duplicate Found
Return
false
Mathematical Concept
If
Length of String
=
Number of Distinct Characters
then
All Characters Are Unique
Otherwise
Duplicate Exists
Example
apple
Length = 5
Distinct = 4
Since
5 ≠ 4
Result
Not Unique
Dry Run
Input
world
| Character | Seen Characters | Duplicate? |
|---|---|---|
| w | {w} | No |
| o | {w,o} | No |
| r | {w,o,r} | No |
| l | {w,o,r,l} | No |
| d | {w,o,r,l,d} | No |
Result
true
Input
apple
| Character | Seen Characters | Duplicate? |
|---|---|---|
| a | {a} | No |
| p | {a,p} | No |
| p | Already Present | Yes |
Return
false
Approach 1 — Using HashSet (Recommended)
The easiest and most common interview solution is using a HashSet.
A HashSet stores only unique elements.
Whenever we try to insert an already existing character,
add() returns false.
Algorithm
- Create a HashSet.
- Traverse the string.
- Insert each character.
- If insertion fails, duplicate found.
- Return false.
- Otherwise return true.
Java Program
import java.util.HashSet;
import java.util.Set;
public class UniqueCharactersHashSet {
public static boolean isUnique(String text) {
Set<Character> seen = new HashSet<>();
for (char ch : text.toCharArray()) {
if (!seen.add(ch)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(isUnique("abcdef"));
System.out.println(isUnique("apple"));
}
}
Output
true
false
Step-by-Step Code Explanation
Create HashSet
Set<Character> seen =
new HashSet<>();
Traverse every character
for(char ch : text.toCharArray())
Insert character
seen.add(ch)
If already exists
return false;
Otherwise
Continue traversal.
Finally
return true;
Dry Run of HashSet Approach
Input
Java
| Character | HashSet | Result |
|---|---|---|
| J | {J} | Continue |
| a | {J,a} | Continue |
| v | {J,a,v} | Continue |
| a | Already Exists | Return false |
Advantages
- Very easy to understand.
- Excellent interview solution.
- Supports Unicode.
- Stops immediately after finding the first duplicate.
- Average lookup time is O(1).
Drawbacks
- Requires extra memory.
- Uses hashing internally.
Approach 2 — Using Boolean Array (ASCII)
If the input contains only ASCII characters, a Boolean array is faster than a HashSet.
Each array index represents one ASCII character.
Example
visited['A']
visited['a']
visited['0']
Visualization
Input
cat
Initially
visited[]
↓
All false
Read
c
visited['c'] = true
Read
a
visited['a'] = true
Read
t
visited['t'] = true
No duplicates.
Algorithm
- Create Boolean array of size 256.
- Traverse the string.
- If character already visited, return false.
- Otherwise mark it visited.
- Return true.
Java Program
public class UniqueCharactersBooleanArray {
public static boolean isUnique(String text) {
boolean[] visited = new boolean[256];
for (char ch : text.toCharArray()) {
if (visited[ch]) {
return false;
}
visited[ch] = true;
}
return true;
}
public static void main(String[] args) {
System.out.println(isUnique("world"));
System.out.println(isUnique("hello"));
}
}
Output
true
false
Step-by-Step Code Explanation
Create Boolean array
boolean[] visited =
new boolean[256];
Traverse string
for(char ch : text.toCharArray())
Check
visited[ch]
If true
Duplicate Found
Otherwise
visited[ch] = true;
Continue.
Time & Space Complexity
| Approach | Time | Extra Space |
|---|---|---|
| HashSet | O(n) | O(k) |
| Boolean Array (ASCII) | O(n) | O(1)* |
Where
- n = Length of the string
- k = Number of distinct characters
Note: For ASCII input, the Boolean array has a fixed size of 256, so its space complexity is considered O(1).
Comparison of Approaches
| Feature | HashSet | Boolean Array |
|---|---|---|
| Interview Friendly | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Performance | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Unicode Support | ✅ | ❌ |
| Implementation | Easy | Easy |
Advantages
- Both approaches provide O(n) time complexity.
- HashSet supports Unicode and dynamic character sets.
- Boolean Array is extremely fast for ASCII input.
- Both stop immediately when a duplicate is found.
Drawbacks
- HashSet requires additional memory.
- Boolean Array works only for ASCII characters.
- Neither approach demonstrates bit-level optimization.
Approach 3 — Using Bit Manipulation (Most Optimized)
Bit Manipulation is one of the most optimized solutions for this problem.
Instead of using a HashSet or Boolean array,
we use a single integer (or long) where each bit represents one character.
This approach is commonly asked in interviews when the input contains only lowercase English letters (a-z).
Why Bit Manipulation?
For lowercase English letters:
a → Bit 0
b → Bit 1
c → Bit 2
...
z → Bit 25
Each bit indicates whether a character has already been seen.
Visualization
Input
abc
Initially
00000000000000000000000000
Read
a
00000000000000000000000001
Read
b
00000000000000000000000011
Read
c
00000000000000000000000111
No duplicate found.
Input
aba
When reading the second
a
Bit is already set.
Return
false
Algorithm
- Initialize an integer mask to 0.
- Traverse the string.
- Compute bit position.
- Check if bit is already set.
- If yes, duplicate found.
- Otherwise set the bit.
- Return true if traversal completes.
Java Program
public class UniqueCharactersBitMask {
public static boolean isUnique(String text) {
int mask = 0;
for (char ch : text.toCharArray()) {
int bit = ch - 'a';
if ((mask & (1 << bit)) != 0) {
return false;
}
mask |= (1 << bit);
}
return true;
}
public static void main(String[] args) {
System.out.println(isUnique("world"));
System.out.println(isUnique("hello"));
}
}
Output
true
false
Dry Run
Input
cat
| Character | Bit Position | Mask (Binary) | Duplicate |
|---|---|---|---|
| c | 2 | 00000100 | No |
| a | 0 | 00000101 | No |
| t | 19 | 10000000000000000101 | No |
Advantages
- Fastest solution.
- Constant extra space.
- Excellent interview discussion.
- Demonstrates low-level optimization.
Drawbacks
- Works only for lowercase English letters.
- Less readable.
- Harder for beginners.
Approach 4 — Using Java Streams
Java Streams provide a concise functional programming solution.
The idea is simple:
- Count distinct characters.
- Compare with string length.
Algorithm
- Convert string into a Stream.
- Count distinct characters.
- Compare with original length.
- Return result.
Java Program
public class UniqueCharactersStreams {
public static boolean isUnique(String text) {
long distinct =
text.chars()
.distinct()
.count();
return distinct == text.length();
}
public static void main(String[] args) {
System.out.println(isUnique("abcdef"));
System.out.println(isUnique("apple"));
}
}
Output
true
false
Advantages
- Modern Java.
- Very concise.
- Functional programming style.
- Easy to read.
Drawbacks
- Stream overhead.
- Less common in interviews.
- Slightly slower than HashSet.
Approach 5 — Using Sorting
Sorting groups identical characters together.
After sorting,
we only need to compare adjacent characters.
Visualization
Input
banana
Sorted
aaabnn
Traverse
a
↓
a
Duplicate Found
Return
false
Algorithm
- Convert string into character array.
- Sort array.
- Compare adjacent characters.
- If equal, duplicate found.
- Otherwise continue.
- Return true.
Java Program
import java.util.Arrays;
public class UniqueCharactersSorting {
public static boolean isUnique(String text) {
char[] characters = text.toCharArray();
Arrays.sort(characters);
for (int i = 1; i < characters.length; i++) {
if (characters[i] == characters[i - 1]) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(isUnique("world"));
System.out.println(isUnique("hello"));
}
}
Output
true
false
Advantages
- No HashSet required.
- Easy to understand.
- Useful when sorting is already needed.
Drawbacks
- Sorting increases time complexity.
- Modifies character order.
- Slower than hashing.
Unicode Considerations
Java uses UTF-16 encoding for String.
Examples
こんにちは
नमस्ते
😊
HashSet
✅ Supports Unicode.
Java Streams
✅ Supports Unicode.
Sorting
✅ Supports Unicode characters.
Boolean Array
❌ Limited to the configured array size (typically ASCII).
Bit Manipulation
❌ Limited to lowercase English letters unless significantly extended.
Edge Cases
| Input | Output |
|---|---|
"" |
true |
"a" |
true |
"aa" |
false |
"abcdef" |
true |
"apple" |
false |
"12345" |
true |
"112345" |
false |
"😊😊" |
false (HashSet/Streams/Sorting) |
Time & Space Complexity
| Approach | Time | Extra Space |
|---|---|---|
| HashSet | O(n) | O(k) |
| Boolean Array | O(n) | O(1)* |
| Bit Manipulation | O(n) | O(1) |
| Java Streams | O(n) | O(k) |
| Sorting | O(n log n) | O(1)** |
Where
- n = Length of the string
- k = Number of distinct characters
*Boolean Array uses fixed-size ASCII storage.
**Java's
Arrays.sort(char[])uses Dual-Pivot Quicksort for primitive arrays and requires only a small recursion stack, so it is commonly treated as O(log n) auxiliary space in practice.
Comparison of All Approaches
| Approach | Interview Friendly | Performance | Unicode Support | Best Use Case |
|---|---|---|---|---|
| HashSet | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ✅ | Recommended interview solution |
| Boolean Array | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ | ASCII-only input |
| Bit Manipulation | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ | Lowercase English letters |
| Java Streams | ⭐⭐⭐⭐ | ⭐⭐⭐ | ✅ | Modern Java |
| Sorting | ⭐⭐⭐⭐ | ⭐⭐⭐ | ✅ | When sorted data is already needed |
Common Interview Mistakes
Mistake 1
Using nested loops.
Wrong complexity
O(n²)
Use HashSet instead.
Mistake 2
Using Bit Manipulation for uppercase or Unicode input.
Example
Java
The bit-mask solution assumes lowercase English letters only.
Mistake 3
Ignoring empty strings.
""
contains no duplicates and should return
true
Mistake 4
Forgetting to stop early.
As soon as a duplicate is found,
return immediately.
Mistake 5
Using Sorting without mentioning complexity.
Sorting increases complexity from
O(n)
to
O(n log n)
Interview Follow-up Questions
Q1. Why is HashSet preferred?
Q2. Why is Bit Manipulation the fastest?
Q3. What assumptions does Bit Manipulation make?
Q4. Which approaches support Unicode?
Q5. Can this be solved without extra space?
Q6. Why is Sorting slower?
Q7. What happens if the string contains emojis?
Q8. Can Java Streams replace HashSet?
Q9. How would you ignore case (A and a)?
Q10. How would you check uniqueness in a file containing millions of characters?
Related Problems
- Remove Duplicate Characters
- Character Frequency
- Detect Duplicate Characters
- First Non-Repeating Character
- Longest Substring Without Repeating Characters
- Permutation Check
- Group Anagrams
- Most Frequent Character
- Sort Characters by Frequency
Key Takeaways
- Checking unique characters is a fundamental String interview problem.
- HashSet is the simplest and most recommended solution.
- Boolean Array is an optimized solution for ASCII input.
- Bit Manipulation provides constant-space optimization for lowercase English letters.
- Java Streams offer a concise functional programming approach.
- Sorting is useful when the input is already being sorted, but it increases time complexity.
Frequently Asked Interview Questions
Q1. Which solution is best for interviews?
The HashSet approach is the most commonly expected answer because it is simple, readable, and works with Unicode.
Q2. Which solution is the most optimized?
For lowercase English letters only, Bit Manipulation is the most optimized because it uses constant extra space and avoids additional collections.
Q3. Why use a Boolean Array?
A Boolean Array provides very fast lookups for ASCII input and avoids hashing overhead.
Q4. Why is Sorting slower?
Sorting requires O(n log n) time before duplicate checking, whereas HashSet-based solutions complete in O(n) average time.
Q5. Can this problem be solved without additional memory?
Yes. By sorting the characters first and then checking adjacent elements, you can avoid auxiliary data structures, but the trade-off is increased time complexity.
Interview Tip
If an interviewer asks:
"How do you check whether a string contains all unique characters?"
Start with the HashSet solution because it is clear, efficient, and production-ready.
Then discuss increasingly optimized alternatives:
- HashSet (recommended)
- Boolean Array (ASCII optimization)
- Bit Manipulation (lowercase English letters)
- Java Streams (functional programming)
- Sorting (no hash-based structure)
Before coding, clarify:
- Is the input limited to lowercase English letters?
- Is it ASCII or full Unicode?
- Are uppercase and lowercase considered different?
- Can additional memory be used?
Discussing these assumptions and trade-offs demonstrates strong problem-solving skills and a solid understanding of Java data structures and algorithms.