输入一个长度为n的数组a,其中有的数据出现一次有的出现两次,返回其中出现两次的数据
不开辟额外空间,时间复杂度O(n)
如输入[1, 1, 2, 3, 5, 3]返回 [1, 3]
输入一个长度为n的数组a,其中有的数据出现一次有的出现两次,返回其中出现两次的数据
不开辟额外空间,时间复杂度O(n)
如输入[1, 1, 2, 3, 5, 3]返回 [1, 3]
这道题像是力扣 260 的变体,可以借鉴其解题思路。
而力扣260传播最广的解法是用 BitMap
缓存遍历进度,用亦或运算的特性a^a===0
来判定数据出现偶数次。这里判定之后,再用&
运算获取判定结果。
在 ES2020-
的环境中需要用 ArrayBuffer
+ DataView
来实现 Bitmap
,现在可以用 BigInt
来糊弄:
function detect(arr){
let spaceLength = 0; // 用来标记数组里作为结果的空间有多长
let bitMap = BigInt(2 ** arr[0]); // BitMap
for(let i = 1; i < arr.length; i++){
const item = arr[i];
const itemLength = BigInt(2 ** item);
// 如果对应的 bit 有偶数次重复的话,经过亦或就变成了0
bitMap ^= itemLength;
if(!(bitMap & itemLength)){
// 把结果写回数组,“避免开辟新的空间”
arr[spaceLength] = item
spaceLength++
}
}
// splice 的时间复杂度有待商榷,据说在 V8 是[1, O(n)]区间
arr.splice(spaceLength);
// 另一种方法,直接修改数组 length,复杂度我没研究过
// arr.length = space Length;
return arr
}
由于用了 BigInt
,可能导致效率低下。
var findDuplicates = function(nums) {
const res = [];
for (const num of nums) {
const absNum = Math.abs(num);
if (nums[absNum - 1] < 0) {
res.push(absNum);
} else {
nums[absNum - 1] = -1 * nums[absNum - 1];
}
}
return res;
};
O(n) 的没想到,O(m + n) 的有一个:
const arr = [1, 1, 2, 3, 5, 3]
let obj = {};
arr.forEach(_ => {
if (obj[_]) {
obj[_]++
} else {
obj[_] = 1
}
})
let res = []
Object.keys(obj).forEach(_ => {
if(obj[_] === 2) {
res.push(Number(_))
}
})
除非限定一些条件,否则O(2n)都不一定有,限定的条件有2条,此外还需要保证最多只有2个重复(这就是力扣中国442问题)
其中N是数组元素数
此外还需要允许计数器变量之类的
function findD(a){
let N=a.length;
let rt=[];
for(let i=0;i<N;i++){
if(a[i]>0){
if(a[a[i]-1]<0) rt.push(a[i]);
a[a[i]-1]=-1*a[a[i]-1];
}else{
if(a[-1*a[i]-1]<0) rt.push(-1*a[i]);
a[-1*a[i]-1]=-1*a[-1*a[i]-1];
}
}
return rt;
}
上面的算法就是一个O(n)的算法啦。
10 回答11.2k 阅读
5 回答4.9k 阅读✓ 已解决
4 回答3.1k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
看了一下,最好的是 @madRain 的解法。
然后又仔细读了下题。要求只找出出现过两次的项。在此题中还有一个已知的限定条件,重复的项最多只会出现2次。所以 @madRain 的解法是最优的。如果没有这个已知项,那是无论如何也无法在O(n)中判断出的,当找出重复项时并不知道后续是否还有重复项,只有在有顺序的数组中才能在一次中完成判断,所以至少要O(2n)。而正因为此题有了这个限定条件,所以可以实现O(n)
要O(n)就只能一次遍历,而且还不能开辟额外空间,即既不能另外做一个缓存列表,也无法使用新的数组。在这种情况下,是无法完成的。
不过,O(n)不行,O(2n)却是可以的。第一步先对数组排序,第二步再比较前后项即可。