Javascript 查找两个数组之间重复项的最快方法
关于在两个数组中查找重复项的最简单方法有很多帖子,但是什么是绝对最快的方法呢?有没有办法避免使用两个for循环并从Javascript 查找两个数组之间重复项的最快方法,javascript,arrays,duplicates,Javascript,Arrays,Duplicates,关于在两个数组中查找重复项的最简单方法有很多帖子,但是什么是绝对最快的方法呢?有没有办法避免使用两个for循环并从O(n^2)time到O(n)time获取函数?我拥有的数组每个包含约1000项。在运行函数之前,我检查哪个数组较长,并将该数组用作toCheckAgainst变量 var containingBoth = []; function checkArrays(toCheck, toCheckAgainst){ for(var i=0;i<toCheck.length;i+=1)
O(n^2)
time到O(n)
time获取函数?我拥有的数组每个包含约1000项。在运行函数之前,我检查哪个数组较长,并将该数组用作toCheckAgainst
变量
var containingBoth = [];
function checkArrays(toCheck, toCheckAgainst){
for(var i=0;i<toCheck.length;i+=1){
for(var j=0;j<toCheckAgainst.length;j+=1){
if (toCheck[i] === toCheckAgainst[j]) {
containingBoth.push(toCheck[i]);
}
}
}
}
var包含两个=[];
函数检查数组(toCheck,toCheckAgainst){
对于(var i=0;i这可能是实现这一点的另一种方法。您当前的解决方案在两个数组上都有循环,在最长的数组上有循环,这会减慢大型数组中的进程,例如,如果一个最长数组有1000个VAL,而较短的数组只有2个VAL,那么您将循环1000个值,以找出不能超过t的重复韩2:那样的话
下面的解决方案循环仅在比另一个阵列短的阵列上,因为我们只对重复感兴趣,即使两个阵列的长度相同,下面的解决方案也会更快,因为在您的解决方案中,您在两个阵列上循环,而下面的代码只在一个阵列上循环
在比较Niles代码和我的代码的速度差异时,是否进行了一些测试,在这里看到了结果,并且使用每个1000个值的数组时,速度大约快了50%
var arr1 = ["Test1", "test2", "test3","test5","test6","test4"];
var arr2 = ["test1", "test4","test5","test6","test2","Test1"];
var result = [];
(arr1.length>arr2.length?arr2:arr1).forEach(function(key) {
if (-1 != (arr1.length>arr2.length?arr1:arr2).indexOf(key) && -1 == result.indexOf(key))
result.push(key);
}, this);
alert(result); //duplicate values arr
编辑以添加示例代码
如果两个数组(长度分别为“k”和“l”)都已排序,则可以在O(n)中执行此操作。可以通过合并两个数组(当然不是在内存中,只是在算法上)来执行此操作,就像使用k+l比较进行合并排序一样
如果两个数组都没有排序,您可以在O(n log n)(例如,使用上面提到的合并排序)中进行O(n²)比较,并且因为您已经可以使用O(n²)中的蛮力来完成任务,所以对数组进行排序在这里是多余的
但并非所有集合都是完全未排序的,特别是当它们很大时。如果我们以快速排序为例,您可以预期O(n log n)与O(n log n)比较的平均值为O(n log n)。但请注意,当集合已排序时,快速排序的最坏情况是O(n²)
如果数组已排序且不包含重复项,则这是一种非常简单的方法:
取较小数组中的单个条目,在较大数组->O(n log n)中对它们进行二进制搜索(二进制搜索为O(log n),并且执行n次)。如果保证较小数组不包含重复项,则甚至不必对其进行排序
小结:你可以比O(n²)快。这取决于输入“快”的实际速度,但在最好的情况下,你可以把它降到O(n)(加上一个小常数),平均降到O(n logn)
'use strict'
var primesieve;
var buffer;
var primelimit;
function clear(where) {
primesieve[where >>> 5] &= ~((1 << (31 - (where & 31))));
}
function get(where) {
return ((primesieve[where >>> 5] >>> ((31 - (where & 31)))) &
1);
}
function nextset(from) {
while (from < primelimit && !get(from)) {
from++;
}
if (from === primelimit && !get(from)) {
return - 1;
}
return from;
}
function fillsieve(n) {
var k,
r,
j;
n = n + 1;
primelimit = n - 1;
k = Math.ceil(n / 32);
if (typeof ArrayBuffer !== 'function') {
buffer = new ArrayBuffer(k * 4);
} else {
buffer = k;
}
primesieve = new Uint32Array(buffer);
while (k--) {
primesieve[k] = 0xffffffff;
}
clear(0);
clear(1);
for (k = 4; k < n; k += 2) {
clear(k);
}
r = Math.floor(Math.sqrt(n));
k = 0;
while (k < n) {
k = nextset(k + 1);
if (k > r || k < 0) {
break;
}
for (j = k * k; j < n; j += 2 * k) {
clear(j);
}
}
}
function approx_limit(prime_pi) {
if (prime_pi < 10) {
return 30;
}
// see first term of expansion of li(x)-li(2)
return Math.ceil(prime_pi * (Math.log(prime_pi * Math.log(prime_pi))));
}
function primes(prime) {
var ret,
k,
count,
i;
ret = [];
k = 0;
i = 0;
count = prime;
while (count--) {
k = nextset(k + 1);
if (k > primelimit || k < 0) {
break;
}
ret[i++] = k;
}
return ret;
}
// very simple binary search
Array.prototype.bsearch = function(needle) {
var mid, lo = 0;
var hi = this.length - 1;
while (lo <= hi) {
mid = Math.floor((lo + hi) / 2);
if (this[mid] > needle) {
hi = mid - 1;
} else if (this[mid] < needle) {
lo = mid + 1;
} else {
return this[mid];
}
}
// assumes no entry "-1", of course
return -1;
};
var limit = 10 * 1000;
var a, b, b_sorted, u;
var a_length, b_length, u_length;
fillsieve(approx_limit(limit));
// the first array is filled with primes, sorted and unique
a = primes(limit);
// the second array gets filled with an unsorted amount of
// integers between the limits 0 (zero) and "limit".
b = [];
for(var i = 0;i < limit;i++){
b[i] = Math.floor( Math.random() * (limit + 1));
}
a_length = a.length;
b_length = b.length;
console.log("Length of array a: " + a_length);
console.log("Length of array b: " + b_length);
var start, stop;
u = [];
// Brute-force
start = performance.now();
for(var i = 0; i < a_length; i++){
for(var j = 0; j< b_length; j++){
if(a[i] == b[j] && a[i] != u[u.length - 1]){
u.push(a[i]);
}
}
}
stop = performance.now();
console.log("Brute force = " + (stop - start));
console.log("u-length = " + u.length);
console.log(u.join(","));
u = [];
b_sorted = [];
// work on copy
for(var i = 0; i < b_length; i++) b_sorted[i] = b[i];
var entry;
// Sort the unsorted array first, than do a binary search
start = performance.now();
// ECMA-script's arrays sort() function sorts lexically
b_sorted.sort(function(a,b){return a - b;});
for(var i = 0; i < a_length; i++){
entry = b_sorted.bsearch(a[i])
if( entry != -1 && entry != u[u.length - 1]){
u.push(entry);
}
}
stop = performance.now();
console.log("Binary search = " + (stop - start));
console.log("u-length = " + u.length);
console.log(u.join(","));
“严格使用”
var分子筛;
var缓冲区;
风险价值上限;
功能清除(其中){
primesieve[where>>>5]&=~(1>>5]>>>((31-(where&31)))&
1);
}
函数nextset(从){
while(fromr | | k<0){
打破
}
对于(j=k*k;jprimelimit | | k<0){
打破
}
ret[i++]=k;
}
返回ret;
}
//非常简单的二进制搜索
Array.prototype.bsearch=函数(指针){
var-mid,lo=0;
var hi=此长度-1;
while(低针){
hi=mid-1;
}否则(此[中间]<针){
lo=中间+1;
}否则{
归还这个[中];
}
}
//当然,假设没有输入“-1”
返回-1;
};
var限值=10*1000;
变量a,b,b_排序,u;
变量a_长度、b_长度、u_长度;
填充筛(近似极限(极限));
//第一个数组充满素数,排序且唯一
a=素数(极限);
//第二个数组将被未排序的
//限制0(零)和“限制”之间的整数。
b=[];
对于(变量i=0;i
这在我的小AMD A8-6600K上运行,使用蛮力算法大约需要56秒,大约需要40毫秒(是的,毫秒)