面试官:如何判断两个数组的内容是否相等

题目

给定两个数组,判断两数组内容是否相等。

  • 不使用排序
  • 不考虑元素位置

例:

js 复制代码
[1, 2, 3] 和 [1, 3, 2] // true
[1, 2, 3] 和 [1, 2, 4] // false

思考几秒:有了😀😀

1. 直接遍历✍

  • 直接遍历第一个数组,并判断是否存在于在第二个数组中
  • 求差集, 如果差集数组有长度,也说明两数组不等(个人感觉比上面的麻烦就不举例了)
js 复制代码
const arr1 =  ["apple", "banana", 1]
const arr2 =  ["apple", 1, "banana"]

function fn(arr1, arr2) {
  // Arrary.some: 有一项不满足 返回false
  // Arrary.indexOf: 查到返回下标,查不到返回 -1
  if (arr1.length !== arr2.length) {
    return false;
  }
  return !arr1.some(item => arr2.indexOf(item)===-1)
}

fn(arr1,arr2) // true
  • 细心的小伙伴就会发现:NaN 会有问题
js 复制代码
const arr1 =  ["apple", "banana", NaN]
const arr2 =  ["apple", NaN, "banana"]

function fn(arr1, arr2) {
  if (arr1.length !== arr2.length) {
    return false;
  }
  return !arr1.some(item => arr2.indexOf(item)===-1)
}

fn(arr1,arr2) // false

Arrary.prototype.indexOf() 是使用的严格相等算法 => NaN值永远不相等

Array.prototype.includes() 是使用的零值相等算法 => NaN值视作相等

  • 严格相等算法: 与 === 运算符使用的算法相同
  • 零值相等 不作为 JavaScript API 公开, -0和0 视作相等,NaN值视作相等,具体参考mdn文档:
  • 使用includes
js 复制代码
const arr1 =  ["apple", "banana", NaN]
const arr2 =  ["apple", NaN, "banana"]

function fn(arr1, arr2) {
  if (arr1.length !== arr2.length) {
    return false;
  }
  return !arr1.some(item => !arr2.includes(item))
}

fn(arr1,arr2) // true

使用includes 确实可以判断NaN了,如果数组元素有重复呢?

js 复制代码
// 重复的元素都是banana
const array1 = ["apple", "banana", "cherry", "banana"];
const array2 = ["banana", "apple", "banana", "cherry"];
// 或者
// 一个重复的元素是banana, 一个是apple
const array1 = ["apple", "banana", "cherry", "banana"];
const array2 = ["banana", "apple", "apple", "cherry"];

由上可知:这种行不通,接下来看看是否能从给数组元素添加标识入手

2. 把重复元素标识编号✍

这个简单:数组 元素重复 转换成val1, val2

js 复制代码
function areArraysContentEqual(arr1, arr2) {
  if (arr1.length !== arr2.length) {
    return false;
  }

  // 重复数组元素 加1、2、3
  const countArr1 = updateArray(arr1)
  const countArr2 = updateArray(arr2)

  /**
   * 
   * @param {*} arr 数组 元素重复 转换成val1, val2
   * @returns 
   */
  function updateArray(arr) {
    const countMap = new Map();
    const updatedArr = [];

    for (const item of arr) {
      if (!countMap.has(item)) {
        // 如果元素是第一次出现,直接添加到结果数组
        countMap.set(item, 0);
        updatedArr.push(item);
      } else {
        // 如果元素已经出现过,添加带有编号的新元素到结果数组
        const count = countMap.get(item) + 1;
        countMap.set(item, count);
        updatedArr.push(`${item}${count}`);
      }
    }
    return updatedArr;
  }
  const flag = countArr1.some(item => !countArr2.includes(item))
  return !flag
}

const array1 = ["apple", "banana", "cherry", "banana"];
const array2 = ["banana", "apple", "banana", "cherry"];

areArraysContentEqual(array1, array2) // true

// 其实这种存在漏洞的
const array3 = ["apple", "banana", "cherry", "banana", 1, '1', '1' ];
const array4 = ["banana", "apple", "banana", "cherry", '1', 1, 1];
// 应该是false
areArraysContentEqual(array3, array4) // true

因为把判断的 转为了字符串 updatedArr.push(${item}${count}) 所以出问题了

3. 统计元素次数(最终方案)✍

js 复制代码
function areArraysContentEqual(arr1, arr2) {
  if (arr1.length !== arr2.length) {
    return false;
  }

  // 创建计数对象,用于记录每个元素在数组中的出现次数
  const countMap1 = count(arr1)
  const countMap2 = count(arr2)

  // 统计数组中的元素出现次数
  function count(arr = []) {
    const resMap = new Map();
    for (const item of arr) {
      resMap.set(item, (resMap.get(item) || 0) + 1);
    }
    return resMap
  }
  // 检查计数对象是否相等
  for (const [key, count] of countMap1) {
    if (countMap2.get(key) !== count) {
      return false;
    }
  }

  return true;
}

const array1 = ["apple", "banana", "cherry", "banana", 1, '1', '11', 11];
const array2 = ["banana", "apple", "banana", "cherry", '1', 1, '11', 11];

areArraysContentEqual(array1, array2) // true

注意事项

这个题需要注意:

  • 先判断长度,长度不等 必然不等
  • 元素可重复
  • 边界情况考虑
    • '1' 和 1 (Object的key是字符串, Map的key没有限制)
    • NaN
    • null undefined

结语:

如果本文对你有收获,麻烦动动发财的小手,点点关注、点点赞!!!👻👻👻

因为收藏===会了

如果有不对、更好的方式实现、可以优化的地方欢迎在评论区指出,谢谢👾👾👾

相关推荐
白晨并不是很能熬夜31 分钟前
【RPC】第 1 篇:全景篇 — 一次 RPC 调用的完整旅程
java·网络·后端·网络协议·面试·rpc·java-zookeeper
d111111111d1 小时前
UAER问题+修复小bug
前端·javascript·笔记·stm32·单片机·嵌入式硬件·学习
kyriewen111 小时前
Next.js:让你的React应用从“裸奔”到“穿衣服”
开发语言·前端·javascript·react.js·设计模式·ecmascript
MXN_小南学前端1 小时前
基于 Vue3 + ECharts 的数据大屏实例(提供gitHub仓库地址)
前端·javascript·echarts
宁雨桥1 小时前
for of,for in以及传统for循环的区别与不同场景下的使用选择
前端·javascript
用户99045017780092 小时前
TrendRadar 热榜监控系统部署与二次开发服务
面试
椰羊~王小美2 小时前
除了前端 JS 配置的国际化,对于 JS 没覆盖到的文本,怎么实现国际化
前端·javascript·状态模式
军军君013 小时前
数字孪生监控大屏实战模板:固体颗粒物监管平台
前端·javascript·vue.js·typescript·前端框架·echarts·less
菜鸟小码3 小时前
MapReduce 核心思想:分而治之,大数据处理的智慧之源
前端·javascript·mapreduce
凤头百灵鸟3 小时前
Python语法进阶篇 --- 单例模式、魔法方法
javascript·python·单例模式