簡體   English   中英

用於在兩個數組中查找公共元素的 Javascript 程序

[英]Javascript Program for find common elements in two array

最近我有一個面試問題如下:讓我們考慮我們有兩個不同長度的排序數組。 需要找到兩個數組中的公共元素。

var a=[1,2,3,4,5,6,7,8,9,10];
var b = [2,4,5,7,11,15];
for(var i=0;i<a.length;i++){
    for(var j=0;j<b.length;j++){
        if(a[i]==b[j]){
            console.log(a[i],b[j])
        }
    }
}

我像上面那樣寫。 面試官說現在假設 a 有 2000 個元素,b 有 3000 個元素。 那么你是如何以更有效的方式寫作的呢?

請用示例代碼解釋您的答案。 這樣我才能更清楚地了解。

您可以通過檢查每個數組的索引來使用嵌套方法,並通過增加索引來查找值。 如果找到相等的值,則增加兩個索引。

時間復雜度:最大 O(n + m),其中n是數組a的長度, m是數組b的長度。

 var a = [1, 2, 3, 4, 5, 6, 8, 10, 11, 15], // left side b = [3, 7, 8, 11, 12, 13, 15, 17], // right side i = 0, // index for a j = 0; // index for b while (i < a.length && j < b.length) { // prevent running forever while (a[i] < b[j]) { // check left side ++i; // increment index } while (b[j] < a[i]) { // check right side ++j; // increment } if (a[i] === b[j]) { // check equalness console.log(a[i], b[j]); // output or collect ++i; // increment indices ++j; } } 

由於數組已排序,因此二進制搜索是關鍵。

基本上,您正在搜索數組中的項目。

您將項目與數組的中間索引進行比較(長度/ 2)

如果兩者相等,則找到它。

如果item劣於數組中間索引的那一項,則將item與索引為index length / 4->(((0 + length / 2)/ 2)的索引進行比較,如果它次於index((length / 2)+長度)/ 2(上部的中間),依此類推。

這樣,如果在示例中您必須在40 000長度的數組中搜索項目,則更糟的是,您發現該項目不在16個比較中而位於數組中:

我正在搜索具有40000個索引的數組中的“某物”,在其中可以找到的最小索引為0,最大索引為39999。

"something" > arr[20000] 讓我們假設。 我知道現在要搜索的最小索引是20001,最大索引是39999。我現在正在搜索中間的索引(20000 + 39999)/ 2。

現在, "something" < arr[30000] ,它將搜索范圍從索引20001限制為29999。(20000 + 30000)/ 2 = 25000。

"something" > arr[25000] ,我必須從25001搜索到29999。(25000 + 30000)/ 2 = 27500

"something" < arr[27500] ,我必須從25001到27499進行搜索。(25000 + 27500)/ 2 = 26250

"something" > arr[26250] ,我必須從26251到27499進行搜索。(26250 + 27500)/ 2 = 26875

"something" < arr[26875] ,我必須從26251到26874進行搜索。(26250 + 26875)/ 2 = 26563

依此類推...當然,您必須四舍五入以避免浮動索引

var iteration = 1;

function bSearch(item, arr)
{
    var minimumIndex = 0;
    var maximumIndex = arr.length - 1;
    var index = Math.round((minimumIndex + maximumIndex) / 2);

    while (true)
    {
        ++iteration;
        if (item == arr[index])
        {
            arr.splice(0, minimumIndex);
            return (true);
        }
        if (minimumIndex == maximumIndex)
        {
            arr.splice(0, minimumIndex);
            return (false);
        }
        if (item < arr[index])
        {
            maximumIndex = index - 1;
            index = Math.ceil((minimumIndex + maximumIndex) / 2);
        }
        else
        {
            minimumIndex = index + 1;
            index = Math.floor((minimumIndex + maximumIndex) / 2);
        }
    }
}

var arrA;
var arrB;

for (var i = 0; i < arrA.length; ++i)
{
    if (bSearch(arrA[i], arrB))
        console.log(arrA[i]);
}
console.log("number of iterations : " + iteration);

由於兩個數組都已排序,因此只保存最新的匹配索引。 然后從這個索引開始你的內循環。

var lastMatchedIndex = 0;
for(var i=0;i<a.length;i++){
    for(var j=lastMatchIndex ;j<b.length;j++){
        if(a[i]==b[j]){
            console.log(a[i],b[j]);
            lastMatchedIndex = j;
            break;
        }
    }
}

=================

更新

正如Xufox在評論中提到的,如果a [i]小於b [i],則u具有中斷循環,因為它沒有繼續循環的意義。

var lastMatchedIndex = 0;
for(var i=0;i<a.length;i++){
    if(a[i]<b[i]){
        break;
    }   
    for(var j=lastMatchIndex ;j<b.length;j++){
        if(a[i]==b[j]){
            console.log(a[i],b[j]);
            lastMatchedIndex = j;
            break;
        }
        if(a[i]<b[j]){
            lastMatchedIndex = j;
            break;
        }         
    }
}

最佳策略是盡量減少比較和數組讀數的策略。

從理論上講,您想要的是替換正在處理的列表,以避免不必要的比較。 考慮到列表已排序,我們知道列表中任何索引左側的數字都不能小於當前索引。

假設以下列表A = [1,5] ,列表B = [1,1,3,4,5,6]且索引ab均從0開始,則您希望代碼如下:

A[a] == 1, B[b] == 1
A[a] == B[b] --> add indexes to results and increase b (B[b] == 1)
A[a] == B[b] --> add indexes to results and increase b (B[b] == 3)
A[a] < B[b] --> don't add indexes to results and increase a (A[a] == 5)
A[a] > B[b] --> don't add indexes to results and increase b (B[b] == 4)
A[a] > B[b] --> don't add indexes to results and increase b (B[b] == 5)
A[a] == B[b] --> add indexes to results and increase b (B[b] == 6)
A[a] < B[b] --> don't add indexes to results and increase a (A is at the end, so we terminate and return results)

以下是我的JavaScript執行上述算法的過程:

 //Parameters var listA = []; var listB = []; //Parameter initialization (function populateListA() { var value = 0; while (listA.length < 200) { listA.push(value); value += Math.round(Math.random()); } })(); (function populateListB() { var value = 0; while (listB.length < 300) { listB.push(value); value += Math.round(Math.random()); } })(); //Searcher function function findCommon(listA, listB) { //List of results to return var results = []; //Initialize indexes var indexA = 0; var indexB = 0; //Loop through list a while (indexA < listA.length) { //Get value of A var valueA = listA[indexA]; var result_1 = void 0; //Get last result or make a first result if (results.length < 1) { result_1 = { value: valueA, indexesInA: [], indexesInB: [] }; results.push(result_1); } else { result_1 = results[results.length - 1]; } //If higher than last result, make new result //Push index to result if (result_1.value < valueA) { //Make new object result_1 = { value: valueA, indexesInA: [indexA], indexesInB: [] }; //Push to list results.push(result_1); } else { //Add indexA to list result_1.indexesInA.push(indexA); } //Loop through list b while (indexB < listB.length) { //Get value of B var valueB = listB[indexB]; //If b is less than a, move up list b if (valueB < valueA) { indexB++; continue; } //If b is greather than a, break and move up list a if (valueB > valueA) { break; } //If b matches a, append index to result result_1.indexesInB.push(indexB); //Move up list B indexB++; } //Move up list A indexA++; } //Return all results with values in both lines return results.filter(function (result) { return result.indexesInB.length > 0; }); } //Run var result = findCommon(listA, listB); //Output console.log(result); 

The easiest way!!

var a = [1,2,3,4,5,6,7,8,9,10];
var b = [2,4,5,7,11,15];

for(let i of a){
  if(b.includes(i)){
    console.log(i)
  }
}

我們可以迭代一個數組,在另一個數組中查找重復數組,但是每次找到匹配項時, 我們將移至匹配元素+ 1,以進行嵌套循環中的下一次迭代 之所以有效,是因為兩個數組都已排序。 因此,每個要比較的數組都較短(從左到右)。

當第二個數組的元素大於第一個數組的元素 (從右到左較短)時,我們也可以打破嵌套循環 ,因為我們永遠找不到匹配項(因為數組是有序的,所以只剩下更大的值),在這里和示例中,在兩個10k元素數組中查找重復項,大約需要15毫秒:

 var arr = []; var arr2 = []; for(let i = 0; i<9999; i++){ arr.push(i); arr2.push(i+4999) } var k = 0;//<-- the index we start to compare var res = []; for (let i = 0; i < arr2.length; i++) { for (let j = k; j < arr.length; j++) { if (arr2[i] === arr[j]) { res.push(arr2[i]); k = j + 1;//<-- updates the index break; } else if (arr[j] > arr2[i]) {//<-- there is no need to keep going break; } } } console.log(res.length) 

我沒有打印res,因為它有5000個元素。

您可以使用第一個數組(無論它們是否排序)構建哈希,然后迭代第二個數組並檢查哈希中是否存在!

 let arr1 = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], arr2 = [15,30,45,60,75,90,105,120,135,150,165] hash = arr1.reduce((h,e)=> (h[e]=1, h), {}), //iterate first array once common = arr2.filter(v=>hash[v]); //iterate secod array once console.log('Cpmmon elements: ', common); 

不確定,但這可能會有所幫助

let num1 = [2, 3, 6, 6, 5];
let num2 = [1, 3, 6, 4];
var array3 = num1.filter((x) => {
  return num2.indexOf(x) != -1
})
console.log(array3);

我有時發現將一個列表轉換為一個哈希集很方便。

var hashA = {};
for(var i=0; i<a.length; i++) {hashA[a[i]] = true;}

然后你可以搜索哈希集。

for(var i=0; i<b.length; i++) {if(hashA[b[i]]) {console.log(b[i]);}}

這當然不如二分搜索快,因為您必須花時間來構建哈希集,但這還不錯,如果您需要保留列表並在未來進行大量搜索,它可能是最佳選擇。 另外,我知道 javascript 對象並不是真正的哈希集,它很復雜,但它大多工作得很好。

老實說,對於 3000 個項目,我不會更改代碼。 這還不足以成為問題。 這將在 30 毫秒內運行。 所以它還取決於它運行的頻率。 一小時一次? 忘掉它。 每毫秒一次? 肯定要優化一下。

如果我們正在討論在兩個數組之間查找公共元素的算法,那么這是我的看法。

function common(arr1, arr2) {
 var newArr = [];
 newArr = arr1.filter(function(v){ return arr2.indexOf(v) >= 0;}) 
 newArr.concat(arr2.filter(function(v){ return newArr.indexOf(v) >= 0;}));
 return newArr;
}

但是如果您也要考慮性能,則還應該嘗試其他方法。

首先在這里檢查javascript循環的性能,它將幫助您找出最佳方法

https://dzone.com/articles/performance-check-on-different-type-of-for-loops-a

https://hackernoon.com/javascript-performance-test-for-vs-for-each-vs-map-reduce-filter-find-32c1113f19d7

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM