Single Number
EasyPrompt
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Example 1:
Input: nums = [2,2,1]
Output: 1
Example 2:
Input: nums = [4,1,2,1,2]
Output: 4
Example 3:
Input: nums = [1]
Output: 1
Constraints:
1 <= nums.length <= 3 * 104-3 * 104 <= nums[i] <= 3 * 104- Each element in the array appears twice except for one element which appears only once.
Approaches
4 approaches with complexity analysis and trade-offs.
This approach uses nested loops to find the single number. For each element in the array, we iterate through the entire array again to count its occurrences. If an element's count is one, it is the unique element.
Algorithm
-
- Iterate through the array with an outer loop from
i = 0ton-1.
- Iterate through the array with an outer loop from
-
- For each element
nums[i], initialize acountvariable to 0.
- For each element
-
- Start an inner loop from
j = 0ton-1.
- Start an inner loop from
-
- Inside the inner loop, if
nums[i]is equal tonums[j], incrementcount.
- Inside the inner loop, if
-
- After the inner loop finishes, check if
countis equal to 1.
- After the inner loop finishes, check if
-
- If
countis 1,nums[i]is the single number. Returnnums[i].
- If
Walkthrough
The brute force method is the most straightforward way to solve the problem, but also the least efficient. The core idea is to check every element and see how many times it appears in the array.
We use two nested loops. The outer loop picks an element, and the inner loop iterates through the entire array to count the occurrences of the picked element. If the count for an element is exactly one, we have found our single number and can return it immediately.
public int singleNumber(int[] nums) { for (int i = 0; i < nums.length; i++) { int count = 0; for (int j = 0; j < nums.length; j++) { if (nums[i] == nums[j]) { count++; } } if (count == 1) { return nums[i]; } } return -1; // Should not be reached given the problem constraints}Complexity
Time
O(n^2)
Space
O(1)
Trade-offs
Pros
Simple to understand and implement.
Uses constant extra space.
Cons
Highly inefficient with a quadratic time complexity.
Will likely result in a 'Time Limit Exceeded' error for large inputs.
This approach involves sorting the array first. Once sorted, all duplicate elements will be adjacent to each other. We can then iterate through the sorted array to find the element that does not have an identical neighbor.
Algorithm
-
- Sort the input array
numsin ascending order.
- Sort the input array
-
- Iterate through the sorted array with a step of 2 (i.e.,
i = 0, 2, 4, ...).
- Iterate through the sorted array with a step of 2 (i.e.,
-
- In each iteration, compare
nums[i]with the next elementnums[i+1].
- In each iteration, compare
-
- If
nums[i]is not equal tonums[i+1], it meansnums[i]is the unique element. Returnnums[i].
- If
-
- If the loop finishes without returning, it implies the single element is the last element in the array. Return
nums[nums.length - 1].
- If the loop finishes without returning, it implies the single element is the last element in the array. Return
Walkthrough
By sorting the array, we can group identical elements together. For example, [4,1,2,1,2] becomes [1,1,2,2,4] after sorting.
After sorting, we can iterate through the array, checking elements in pairs. If nums[i] is not equal to nums[i+1], then nums[i] must be the single element because its pair would have been at nums[i+1]. We must be careful with the boundary conditions, especially the last element, which could be the single number if all preceding elements form pairs.
import java.util.Arrays; public int singleNumber(int[] nums) { Arrays.sort(nums); for (int i = 0; i < nums.length - 1; i += 2) { if (nums[i] != nums[i+1]) { return nums[i]; } } // If the loop completes, the single element is the last one return nums[nums.length - 1];}Complexity
Time
O(n log n)
Space
O(log n) to O(n)
Trade-offs
Pros
More efficient than the brute-force approach.
Conceptually simple after sorting.
Cons
Time complexity is dominated by the sorting algorithm, which is typically O(n log n), not linear.
The space complexity of sorting in-place can be O(log n) or O(n) for some algorithms, which is not constant.
This approach uses a hash set to keep track of the elements encountered. When we see a number for the first time, we add it to the set. When we see it for the second time, we remove it. The last remaining number in the set is the single one.
Algorithm
-
- Initialize an empty hash set.
-
- Iterate through each number
numin the input arraynums.
- Iterate through each number
-
- Check if
numis present in the hash set.
- Check if
-
- If it is present, remove
numfrom the set.
- If it is present, remove
-
- If it is not present, add
numto the set.
- If it is not present, add
-
- After the loop, the hash set will contain exactly one element.
-
- Return this single element.
Walkthrough
A hash set provides average O(1) time complexity for add, remove, and contains operations. We can leverage this to solve the problem in linear time.
We iterate through the input array. For each number, we try to add it to the set. If the number is already in the set (which add method can tell us by returning false), it means we have seen it once before, so this is its second appearance. In this case, we remove it from the set. If the number is not in the set, we add it.
After iterating through all the numbers, the hash set will contain only one element: the number that appeared an odd number of times (once, in this case).
import java.util.HashSet;import java.util.Set; public int singleNumber(int[] nums) { Set<Integer> set = new HashSet<>(); for (int num : nums) { if (!set.add(num)) { // If add returns false, it means the element was already in the set set.remove(num); } } // The set will have only one element, which is the single number return set.iterator().next();}Complexity
Time
O(n)
Space
O(n)
Trade-offs
Pros
Achieves linear time complexity, O(n).
Easy to understand the logic.
Cons
Requires extra space proportional to the number of unique elements, O(n) in the worst case.
Does not meet the constant space complexity requirement of the problem.
This is the most optimal approach, satisfying both linear time and constant space constraints. It leverages the properties of the XOR (exclusive OR) bitwise operator. The XOR of a number with itself is 0, and the XOR of a number with 0 is the number itself. By XORing all numbers in the array, the pairs cancel out, leaving only the single number.
Algorithm
-
- Initialize an integer variable
resultto 0.
- Initialize an integer variable
-
- Iterate through each number
numin the input arraynums.
- Iterate through each number
-
- In each iteration, update
resultby performing a bitwise XOR with the current number:result = result ^ num.
- In each iteration, update
-
- After the loop completes, the value of
resultwill be the single number that appears only once.
- After the loop completes, the value of
-
- Return
result.
- Return
Walkthrough
The XOR operation has two key properties that are useful here:
- A number XORed with itself results in 0 (e.g.,
x ^ x = 0). - A number XORed with 0 results in the number itself (e.g.,
x ^ 0 = x). - XOR is commutative and associative, meaning the order of operations doesn't matter.
We can initialize a variable, say a, to 0. Then, we iterate through the array and XOR each element with a. For any number that appears twice, say x, it will be XORed into the accumulator twice: (... ^ x ... ^ x ...). Due to the properties of XOR, this is equivalent to (... ^ (x ^ x) ...) which is (... ^ 0 ...). So, all the paired numbers will effectively cancel each other out.
The single number, say y, appears only once. It will be XORed into the accumulator once. The final result will be 0 ^ y, which is y.
For example, with nums = [4,1,2,1,2], the calculation would be 0 ^ 4 ^ 1 ^ 2 ^ 1 ^ 2 = 4 ^ (1 ^ 1) ^ (2 ^ 2) = 4 ^ 0 ^ 0 = 4.
public int singleNumber(int[] nums) { int result = 0; for (int num : nums) { result ^= num; } return result;}Complexity
Time
O(n)
Space
O(1)
Trade-offs
Pros
Extremely efficient with O(n) time complexity.
Uses O(1) constant extra space.
Satisfies all problem constraints.
Cons
The logic might be less intuitive for those unfamiliar with bitwise operations.
Solutions
Solution
public class Solution { public int SingleNumber(int[] nums) { return nums.Aggregate(0, (a, b) => a ^ b); }}class Solution {public int singleNumber(int[] nums) { int ans = 0; for (int v : nums) { ans ^= v; } return ans; }}/** * @param {number[]} nums * @return {number} */ var singleNumber = function ( nums,) { return nums.reduce((a, b) => a ^ b);};class Solution {public: int singleNumber(vector<int> &nums) { int ans = 0; for (int v : nums) { ans ^= v; } return ans; }};''' >>> from functools import reduce >>> reduce(lambda x, y: x ^ y, [3, 5, 3]) 5 ''' from functools import reduce class Solution : def singleNumber ( self , nums : List [ int ]) -> int : return reduce ( lambda x , y : x ^ y , nums ) ############ class Solution ( object ): def singleNumber ( self , nums ): """ :type nums: List[int] :rtype: int """ for i in range ( 1 , len ( nums )): nums [ 0 ] ^= nums [ i ] return nums [ 0 ]Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.