给定一个非空整数数组,除了某个元素只出现了一次,其余元素均出现两次。找出只出现了一次的数组。
方法1
const uniqueNum = (nums) {
const numsGroup = nums.map(num => nums.filter(
v => v === num));
return numsGroup.find(num => num.length === 1)[0]
}
思路:
- 使用map遍历数组
- 使用filter再次遍历,最终会得到一个二维数组
- 查找二维数组中长度为1的元素,取当前元素的第0个即可得到目标元素
复杂度分析
- 时间复杂度:map嵌套filter做了两次遍历,时间复杂度为O(),find只做了一次遍历,复杂度为O(n),所以最终的时间复杂度是O()
- 空间复杂度:
numsGroup数组会存储 n 个子数组- 每个子数组的长度等于原数组中对应元素的出现次数(至少1次,最多 n 次)
- 最坏情况(所有元素相同):每个子数组长度为 n ,总空间为 n * n = n²
- 平均情况(其他元素出现2次,仅1个元素出现1次):空间为 (n-1)*2 + 1 = 2n-1 ,仍属于 O(n) (但最坏情况是 O(n²) )
- 最终的时间复杂度和空间复杂度都为O()
方法2
const uniqueNum = (nums: number[]): number => {
let result = 0;
for (const num of nums) {
result ^= num; // 等价于 result = result ^ num
}
return result;
}
思路
- 遍历数组,使用异或进行判断,异或的特性为相同数字异或结果为0;
- 当前数组进行异或判断之后只有目标元素不为0; 复杂度分析
- 时间复杂度:O(n),数组仅遍历一次,因此复杂度为O(n);
- 空间复杂度:O(1),只有result声明了一次常数级额外空间;
方法3
const uniqueNum = (nums: number[]): number => {
return nums.filter(num => {
nums.indexOf(num) === nums.lastIndexOf(num)
})[0];
}
思路
- 使用filter过滤当前数组中第一个下标和最后一个下标一样的数组,产生一个新的数组;
- 只有唯一出现的数组两次下标一致,取第0个元素即可; 复杂度分析
- 时间复杂度:O(),indexOf需要遍历两次数组,因此复杂度为O();
- 空间复杂度:O(1),声明了一次常数级额外空间;
总结 从复杂度和代码实现上来看,异或的方式为最优选,复杂度也是最小的。