大厂面试算法之两个数组求交集

510 阅读3分钟

给定两个数组,用一个函数计算出二者交集。

let num1 = [1,2,2,1];
let num2 = [2,2]; 
//求出[2,2]
let num1 = [4,9,5];
let num2 = [9,4,9,8,4];
//求出[4,9]

方法一

存哈希表

由于同一个数字在两个数组中都可能出现多次,因此需要用哈希表记录每个数字出现的次数。对于同一个数字,其在交集中出现的次数等于该数字在两个数组中出现次数的最小值。

首先遍历第一个数组,并在哈希表中记录第一个数组中的每个数字以及对应出现的次数,然后遍历第二个数组,对于第二个数组中的每个数字,如果在哈希表中存在这个数字,则将该数字添加到答案,同时减少哈希表中该数字出现的次数。

为了降低空间复杂度,首先遍历较短的数组并在哈希表中记录每个数字以及对应出现的次数,然后遍历较长的数组得到交集。

const intersect = (num1, num2) => {
  const map = {};
  const res = [];
  for (const n1 of num1) { // 存下num1数字的出现次数
    if (map[n1]) {
      map[n1]++;  
    } else {         
      map[n1] = 1; 
    }
  }
  for (const n2 of num2) { // 遍历num2看看有没有数字在num1出现过
    const val = map[n2];
    if (val > 0) {            // 出现过
      res.push(n2);         // 推入res数组
      map[n2]--;            // 匹配掉一个,就少了一个
    }
  }
  return res;
};

运行结果:

let num1 = [1,2,2,1];
let num2 = [2,2]; 
console.log(intersect(num1,num2));		//[2,2]

方法二

双指针方式

如果两个数组是有序的,则可以便捷地计算两个数组的交集。

首先对两个数组进行排序,然后使用两个指针遍历两个数组。

初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,将该数字添加到答案,并将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。

const intersect = (num1, num2) => {
  num1.sort((a, b) => a - b);
  num2.sort((a, b) => a - b); // 先排序,使得重复的元素相邻出现
  const res = [];
  let p1 = 0;                  // 两个指针
  let p2 = 0;
  while (p1 < num1.length && p2 < num2.length) { // 用 && 因为有一个越界了就不能找交集
    if (num1[p1] > num2[p2]) {        // p1指向的数大,移动p2,期待遇到一样大的
      p2++;
    } else if (num1[p1] < num2[p2]) { // 类似
      p1++;
    } else {                   // 遇到相同的,推入res数组,两个指针同时移动考察下一个
      res.push(num1[p1]);
      p1++;
      p2++;
    }
  }
  return res;
};

运行结果:

let num1 = [4,9,5];
let num2 = [9,4,9,8,4];
console.log(intersect(num1,num2));		//[4,9]

方法三

最简单的双重循环

const intersect = (num1, num2) => {
    const res = [];
    for(let i=0;i<num1.length;i++){
        for(let j=0;j<num2.length;j++){
            if(num1[i] == num2[j]){
                res.push(num1[i]);
                num1.splice(i,1); 
                i--;		//删除元素后索引需前移
                num2.splice(j,1); 
                break;
            }
        }
    }
    return res;
};

不解释

前端优选