Find the number that appears once, and other numbers twice.
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a non-empty integer array nums in which every element appears exactly twice, except for one element that appears exactly once. Return that single element. The order of the array is arbitrary; the two copies of a value are not necessarily adjacent.
Constraints: 1 ≤ n ≤ 3 × 10^4, n is odd, values fit in a 32-bit signed integer and may be negative or zero. Exactly one element appears once.
Example 1
nums = [4, 1, 2, 1, 2]
answer = 4 // 1 and 2 each appear twice, 4 appears once
Example 2
nums = [2, 2, 1]
answer = 1
Example 3
nums = [7, 0, 7]
answer = 0 // the answer itself can be 0
Approach 1: Brute force
Intuition. The statement is about counts, so count. For each element, scan the whole array and count how many times its value occurs. The first element whose count is 1 is the answer. There is nothing clever here, but it is a correct baseline against which the faster versions can be tested.
Algorithm.
- For every index
i: - Count the indices
jwithnums[j] == nums[i]. - If the count is
1, returnnums[i]. - Return
-1if nothing is found (cannot happen with valid input).
static int bruteForce(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
int count = 0;
for (int j = 0; j < n; j++) {
if (nums[j] == nums[i]) count++;
}
if (count == 1) return nums[i];
}
return -1;
}
Complexity. Time O(n^2): each of the n elements triggers a full scan. Space O(1).
Approach 2: Better, count with a hash map (or sort)
Intuition. Counting each value once instead of re-scanning is the standard fix for a nested counting loop: a hash map from value to frequency is built in one pass, and a second pass over the map picks out the key with frequency 1.
Algorithm.
- Build
freq, a map from value to the number of times it occurs. - Iterate the map entries and return the key whose value is
1.
static int better(int[] nums) {
Map<Integer, Integer> freq = new HashMap<>();
for (int x : nums) freq.merge(x, 1, Integer::sum);
for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
if (e.getValue() == 1) return e.getKey();
}
return -1;
}
Complexity. Time O(n) on average: one pass to build the map and one pass over at most n entries. Space O(n): the map holds about n / 2 + 1 keys.
If you would rather not pay for the map, sort first. In a sorted array every pair sits side by side, so pairs occupy positions (0, 1), (2, 3), ... until the single element breaks the pattern: the first even index i with a[i] != a[i + 1] is the answer, and if no pair is broken the single element is the last one.
static int betterSorting(int[] nums) {
int[] a = nums.clone();
Arrays.sort(a);
for (int i = 0; i + 1 < a.length; i += 2) {
if (a[i] != a[i + 1]) return a[i];
}
return a[a.length - 1];
}
This is O(n log n) time and O(n) for the defensive copy (or O(1) extra if you are allowed to sort in place). Why does comparing a[i] with a[i + 1] at even indices only suffice? Before the single element, every even index begins a pair, so the test passes. The single element lands at some even index s (because the s / 2 pairs before it fill s positions), and a[s + 1] is the first element of the next pair, which differs from it. After that, the pattern is shifted and we never look at it again because we return immediately.
Both variants are fine answers, but they still use extra memory or extra time. The interviewer is waiting for the next one.
Approach 3: Optimal, XOR everything
Intuition. Bitwise XOR has three properties that together solve the problem in one pass with no memory:
a ^ a = 0: a value XORed with itself cancels out.a ^ 0 = a: zero is the identity.- XOR is commutative and associative, so the order in which we combine values does not matter.
XOR all the elements together. Reorder them mentally so that each pair is adjacent: every pair becomes 0, the zeros vanish, and the only thing left is the single element. This works bit by bit: for each bit position, the paired values contribute an even number of ones, so the parity of that bit across the whole array is exactly the bit of the single element.
Algorithm.
- Set
x = 0. - For every element
v, setx = x ^ v. - Return
x.
static int optimal(int[] nums) {
int x = 0;
for (int v : nums) x ^= v;
return x;
}
Dry run on nums = [4, 1, 2, 1, 2] (values in binary):
| v | binary | x after |
|---|---|---|
| 4 | 100 | 100 |
| 1 | 001 | 101 |
| 2 | 010 | 111 |
| 1 | 001 | 110 |
| 2 | 010 | 100 = 4 |
Complexity. Time O(n): one pass. Space O(1): a single integer.
A note on negative numbers: Java’s int is a two’s-complement value and ^ operates on all 32 bits, including the sign bit, so negatives need no special handling. XORing Integer.MIN_VALUE with two copies of Integer.MAX_VALUE correctly yields Integer.MIN_VALUE, and the test in the Java file checks exactly that.
Edge cases and pitfalls
- Single element (
[1]). The answer is that element; the XOR of one value is itself. - The answer is zero (
[7, 0, 7]). XOR returns0correctly. Be careful if you were tempted to use0as a “not found” marker: it is a legal answer. - Negative numbers. Fine for all approaches; XOR works on the full bit pattern.
- Returning
-1from the brute force and map versions. Valid input always has a single element, so that line is never reached; it exists only so the method compiles with a return on every path. Do not mistake-1for a legitimate answer in a problem where-1can be an array value. - Why XOR, not addition? Summing and subtracting pairs is not possible because we do not know which values are paired. XOR does not need to know: cancellation happens automatically.
- Exactly-twice assumption. The XOR trick depends on every other value appearing an even number of times. If other values can appear three times, the parity argument breaks and you need a per-bit count modulo 3 instead (see Single Number II). If two values appear once, XOR gives their combination and you need one more step to separate them (Single Number III).
Related problems
- Single Number - I is this problem seen from the bit manipulation side of the sheet.
- Single Number - III has two singles; XOR gives
a ^ b, then one set bit splits the array into two groups. - Single element in a Sorted Array is the sorted version, where the pair-index parity argument from Approach 2 becomes a binary search.
- Find missing number uses the same XOR cancellation against the range
1..n.