Since the value of input array ranges from 1..n, and we're going to find the duplicate and missing, we can use input array itself as hash table and index as key (value - 1), then iterate every number and mark the number as negative (seen).
When seeing value = 3 (
A[i]), we markA[2]as negative.
- The number is already negative, we've seen this before, it's duplicate.
- Then iterate again to see which number has not been seen (positive).
fun findErrorNums(nums: IntArray): IntArray {
var duplicate = 0
for (i in 0 until nums.size) {
val value = nums[i]
// We see value, we mark `A[value - 1]` as negative.
// When seeing 3, we mark `A[2]` as negative.
if (nums[value - 1] < 0) {
duplicate = value
}
nums[value - 1] = -abs(nums[value - 1])
}
var missing = 0
for (i in 0 until nums.size) {
// When A[2] is positive, then we didn't see 3.
// When A[i] is positive, then we didn't see i + 1.
// When seeing i + 1, we mark `A[i]` as negative.
if (nums[i] > 0) {
missing = i + 1
break
}
}
return intArrayOf(duplicate, missing)
}- Time Complexity:
O(n). - Space Complexity:
O(1).
See My Notes
We see A[i] = 4, then we should place it to A[3] (A[A[i] - 1] should be 4). Then iterate again to find the duplicate number A[i] that satisfies A[i] != i + 1.
fun findErrorNums(nums: IntArray): IntArray {
// duplicate, missing
val ans = IntArray(2)
val n = nums.size
for (i in 0 until n) {
while (nums[i] - 1 in 0 until n && nums[i] != nums[nums[i] - 1]) nums.swap(i, nums[i] - 1)
}
// Or equivalent to:
// var i = 0
// while (i < n) {
// if (nums[i] - 1 in 0 until n && nums[i] != nums[nums[i] - 1]) {
// nums.swap(i, nums[i] - 1)
// } else {
// i++
// }
// }
// 0, 1, 2, 3
// 1, 2, 2, 4
// index 2 should be 3 (missing), but it's 2 (duplicate)
// duplicate is 2, missing is 3
for (i in 0 until n) {
if (i + 1 != nums[i]) {
ans[0] = nums[i]
ans[1] = i + 1
}
}
return ans
}