You have a set of integers s
, which originally contains all the numbers from 1
to n
. Unfortunately, due to some error, one of the numbers in s
got duplicated to another number in the set, which results in repetition of one number and loss of another number.
You are given an integer array nums
representing the data status of this set after the error.
Find the number that occurs twice and the number that is missing and return them in the form of an array.
Example 1:
Input: nums = [1,2,2,4] Output: [2,3]
Example 2:
Input: nums = [1,1] Output: [1,2]
Constraints:
2 <= nums.length <= 104
1 <= nums[i] <= 104
Given an integer array nums
containing numbers from 1 to n
, where one number is duplicated and another is missing, find the duplicate and missing numbers. Return them as an array.
This problem can be solved using several approaches:
This approach leverages the properties of sums.
Approach:
n
is given by the formula n * (n + 1) / 2
.nums
.missing - duplicate
).nums
to remove duplicates and calculate the sum of the unique numbers.Time Complexity: O(n) - due to summing and creating a set. Space Complexity: O(n) - to store the set of unique numbers.
Code (Python):
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
n = len(nums)
expected_sum = n * (n + 1) // 2
actual_sum = sum(nums)
sum_unique = sum(set(nums))
duplicate = actual_sum - sum_unique
missing = expected_sum - sum_unique
return [duplicate, missing]
Code (Java):
import java.util.HashSet;
import java.util.Set;
class Solution {
public int[] findErrorNums(int[] nums) {
int n = nums.length;
int expectedSum = n * (n + 1) / 2;
int actualSum = 0;
for (int num : nums) {
actualSum += num;
}
Set<Integer> uniqueNums = new HashSet<>();
int sumUnique = 0;
for (int num : nums) {
if (uniqueNums.add(num)) {
sumUnique += num;
}
}
int duplicate = actualSum - sumUnique;
int missing = expectedSum - sumUnique;
return new int[]{duplicate, missing};
}
}
Approach:
nums
.n
.Time Complexity: O(n) - due to iterating through the array and the range 1 to n. Space Complexity: O(n) - to store the hash table.
Code (Python):
from collections import Counter
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
count = Counter(nums)
n = len(nums)
duplicate = 0
missing = 0
for i in range(1, n + 1):
if count[i] == 2:
duplicate = i
if count[i] == 0:
missing = i
return [duplicate, missing]
Code (Java):
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] findErrorNums(int[] nums) {
Map<Integer, Integer> count = new HashMap<>();
for (int num : nums) {
count.put(num, count.getOrDefault(num, 0) + 1);
}
int n = nums.length;
int duplicate = 0;
int missing = 0;
for (int i = 1; i <= n; i++) {
if (count.getOrDefault(i, 0) == 2) {
duplicate = i;
}
if (count.getOrDefault(i, 0) == 0) {
missing = i;
}
}
return new int[]{duplicate, missing};
}
}
This is a more advanced and efficient solution.
Approach:
The core idea is that XORing a number with itself results in 0, and XORing with 0 leaves the number unchanged. We use this property:
nums
with the numbers from 1 to n
. The result (xs
) will be the XOR of the duplicate and missing numbers (since the other numbers cancel out).xs
. This bit will be different between the duplicate and missing numbers.Time Complexity: O(n) Space Complexity: O(1)
Code (Python):
class Solution:
def findErrorNums(self, nums: List[int]) -> List[int]:
xs = 0
for i, x in enumerate(nums, 1):
xs ^= i ^ x
a = 0
lb = xs & -xs
for i, x in enumerate(nums, 1):
if i & lb:
a ^= i
if x & lb:
a ^= x
b = xs ^ a
return [a if a in nums else b, b if b not in nums else a]
The Java, C++, Go, TypeScript, and Rust implementations for this bit manipulation solution are similar in structure to the Python code but with syntax specific to those languages. They follow the same algorithm steps. Due to length constraints I'm omitting them here, but they would follow the same logical steps as described. The provided solutions above already include several examples of bit manipulation solutions.
Remember to choose the solution that best suits your needs and understanding. The mathematical approach is easier to understand, while the bit manipulation approach is the most efficient in terms of space complexity. The hash table approach offers a good balance.