int* findErrorNums(int* nums, int numsSize, int* returnSize) { int* errorNums = malloc(sizeof(int) * 2); *returnSize = 2; qsort(nums, numsSize, sizeof(int), cmp); int prev = 0; for (int i = 0; i < numsSize; i++) { int curr = nums[i]; if (curr == prev) { errorNums[0] = prev; } elseif (curr - prev > 1) { errorNums[1] = prev + 1; } prev = curr; } if (nums[numsSize - 1] != numsSize) { errorNums[1] = numsSize; } return errorNums; }
[sol1-JavaScript]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var findErrorNums = function(nums) { const errorNums = newArray(2).fill(0); const n = nums.length; nums.sort((a, b) => a - b); let prev = 0; for (let i = 0; i < n; i++) { const curr = nums[i]; if (curr === prev) { errorNums[0] = prev; } elseif (curr - prev > 1) { errorNums[1] = prev + 1; } prev = curr; } if (nums[n - 1] !== n) { errorNums[1] = n; } return errorNums; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcfindErrorNums(nums []int) []int { ans := make([]int, 2) sort.Ints(nums) pre := 0 for _, v := range nums { if v == pre { ans[0] = v } elseif v-pre > 1 { ans[1] = pre + 1 } pre = v } n := len(nums) if nums[n-1] != n { ans[1] = n } return ans }
var findErrorNums = function(nums) { const errorNums = newArray(2).fill(0); const n = nums.length; const map = newMap(); for (const num of nums) { map.set(num, (map.get(num) || 0) + 1); } for (let i = 1; i <= n; i++) { const count = map.get(i) || 0; if (count === 2) { errorNums[0] = i; } elseif (count === 0) { errorNums[1] = i; } } return errorNums; };
[sol2-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
funcfindErrorNums(nums []int) []int { cnt := map[int]int{} for _, v := range nums { cnt[v]++ } ans := make([]int, 2) for i := 1; i <= len(nums); i++ { if c := cnt[i]; c == 2 { ans[0] = i } elseif c == 0 { ans[1] = i } } return ans }
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。需要遍历数组并填入哈希表,然后遍历从 1 到 n 的每个数寻找错误的集合。
用 x 和 y 分别表示重复的数字和丢失的数字。考虑上述 2n 个数字的异或运算结果 xor,由于异或运算 \oplus 满足交换律和结合律,且对任何数字 a 都满足 a \oplus a = 0 和 0 \oplus a = a,因此 xor} = x \oplus x \oplus x \oplus y = x \oplus y,即 x 和 y 的异或运算的结果。
由于 x \ne y,因此 xor} \ne 0,令 lowbit} = \textit{xor}&(-\textit{xor}),则 lowbit 为 x 和 y 的二进制表示中的最低不同位,可以用 lowbit 区分 x 和 y。
得到 lowbit 之后,可以将上述 2n 个数字分成两组,第一组的每个数字 a 都满足 a&\textit{lowbit} = 0,第二组的每个数字 b 都满足 b&\textit{lowbit} \ne 0。
遍历结束之后,num}_1 为第一组的全部数字的异或结果,num}_2 为第二组的全部数字的异或结果。由于同一个数字只可能出现在其中的一组,且除了 x 和 y 以外,每个数字一定在其中的一组出现 2 次,因此 num}_1 和 num}_2 分别对应 x 和 y 中的一个数字,但是具体对应哪个数还未知。
为了知道 num}_1 和 num}_2 分别对应 x 和 y 中的哪一个数字,只需要再次遍历数组 nums 即可。如果数组中存在元素等于 num}_1,则有 x=\textit{num}_1 和 y=\textit{num}_2,否则有 x=\textit{num}_2 和 y=\textit{num}_1。
funcfindErrorNums(nums []int) []int { xor := 0 for _, v := range nums { xor ^= v } n := len(nums) for i := 1; i <= n; i++ { xor ^= i } lowbit := xor & -xor num1, num2 := 0, 0 for _, v := range nums { if v&lowbit == 0 { num1 ^= v } else { num2 ^= v } } for i := 1; i <= n; i++ { if i&lowbit == 0 { num1 ^= i } else { num2 ^= i } } for _, v := range nums { if v == num1 { return []int{num1, num2} } } return []int{num2, num1} }
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。整个过程需要对数组 nums 遍历 3 次,以及遍历从 1 到 n 的每个数 2 次。