JS面试题之如何判断两个数组的内容是否相等

 更新时间:2023年10月27日 09:15:12   作者:前端技术栈  
这篇文章主要为大家详细介绍了JavaScript面试的常考题,即如何判断两个数组的内容是否相等,文中的示例方法讲解详细,需要的小伙伴可以参考一下

题目

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

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

例:

[1, 2, 3] 和 [1, 3, 2] // true
[1, 2, 3] 和 [1, 2, 4] // false

思考几秒:有了

1. 直接遍历

直接遍历第一个数组,并判断是否存在于在第二个数组中

求差集, 如果差集数组有长度,也说明两数组不等(个人感觉比上面的麻烦就不举例了)

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 会有问题

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

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了,如果数组元素有重复呢?

// 重复的元素都是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

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. 统计元素次数(最终方案)

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

4. 评论区大佬方案(+1、-1)

  • 只需要一个对象
  • 遍历第一个数组就 +1
  • 遍历第二个数组就 - 1
  • 最后遍历对象,只要不是都是 0 就等于不匹配

这样就不需要俩个对象了,而且第二个遍历的时候如果找不到这个值的话也可以直接退出了

function areArraysContentEqual3(arr1, arr2) {
  if (arr1.length !== arr2.length) {
    return false;
  }
 
  const countMap = new Map();
 
  // 计数第一个数组的元素
  for (const item of arr1) {
    countMap.set(item, (countMap.get(item) || 0) + 1);
  }
 
  // 比较第二个数组与计数
  for (const item of arr2) {
    const val = countMap.get(item);
    if (val === undefined || val <= 0) {
      return false;
    }
    countMap.set(item, val - 1);
  }
 
  return true;
}

5. 评论区大佬方案(操作第二个数组)

遍历第一个数组,在第二个数组找到就删除第二个数组中对应的元素,没有找到直接不等,最后再判断一下第二个数组的长度即可。实际使用中一般不直接操作原数组,浅复制一下就好

可能没有前几个性能好,但是想法还是很好的点赞~

function areArraysContentEqual2(arr1=[], arr2=[]) {
  arr2 = [...arr2]
  if (arr1.length !== arr2.length) {
    return false;
  }
 
  arr1.some(item => {
    // 找到元素在第二个数组中的位置
    const index = arr2.findIndex(item1 => {
        // 这里有坑 下面会讲到
      if (isNaN(item) && isNaN(item1)) {
        return true
      }
      return item ===item1
    })
    if (index !== -1 ) {
      arr2.splice(index, 1)
    }
  })
  return !arr2.length
}

NaN 判断的时候,会有隐式转换(参数不是数字时会隐式转换)

Number.isNaN 判断才是严格相等

isNaN('11') // false
isNaN('ccc') // true
isNaN('a') // true
isNaN(NaN) // true
 
Number.isNaN('11') // false
Number.isNaN('ccc') // false
Number.isNaN('a') // false
Number.isNaN(NaN) // true

第五点(NaN判断问题修复)

function areArraysContentEqual(arr1=[], arr2=[]) {
  arr2 = [...arr2]
  if (arr1.length !== arr2.length) {
    return false;
  }
 
  const compare = (item1, item2) => {
    if (Number.isNaN(item1) && Number.isNaN(item2)) {
      return true;
    }
    return item1 === item2;
  };
 
  arr1.some(item => {
    // 找到元素在第二个数组中的位置
    const index = arr2.findIndex(item1 => compare(item, item1))
    if (index !== -1 ) {
      arr2.splice(index, 1)
    }
  })
  return !arr2.length
}

注意事项

这个题需要注意:

1.先判断长度,长度不等 必然不等

2.元素可重复

3.边界情况考虑

  • '1' 和 1 (Object的key是字符串, Map的key没有限制)
  • NaN
  • null undefined

到此这篇关于JS面试题之如何判断两个数组的内容是否相等的文章就介绍到这了,更多相关JS判断数组内容是否相等内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • javascript操作excel生成报表全攻略

    javascript操作excel生成报表全攻略

    这篇文章主要介绍了如何使用javascript操作excel生成报表,需要的朋友可以参考下
    2014-05-05
  • JavaScript实现获取img的原始尺寸的方法详解

    JavaScript实现获取img的原始尺寸的方法详解

    在微信小程序开发时,它的image标签有一个默认高度,这样你的图片很可能出现被压缩变形的情况,所以就需要获取到图片的原始尺寸对image的宽高设置,本文就来分享一下JavaScript实现获取img的原始尺寸的方法吧
    2023-03-03
  • jquery实用技巧之输入框提示语句

    jquery实用技巧之输入框提示语句

    输入有效信息时会有一些提示语,比如“请输入用户名”和“请输入密码”等语言,这篇文章就为大家介绍js实用技巧之输入框提示语句的实现方法,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Avalon中文长字符截取、关键字符隐藏、自定义过滤器

    Avalon中文长字符截取、关键字符隐藏、自定义过滤器

    avalon是一个简单易用迷你的MVVM框架。通过本文给大家介绍Avalon中文长字符截取、关键字符隐藏、自定义过滤器的相关资料,需要的朋友一起学习吧
    2016-05-05
  • Sublime Text 3插件Minify的安装与使用(js代码压缩)

    Sublime Text 3插件Minify的安装与使用(js代码压缩)

    这篇文章主要介绍了Sublime Text 3插件Minify的安装与使用(js代码压缩),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-01-01
  • uniapp实现地图点聚合功能的详细教程

    uniapp实现地图点聚合功能的详细教程

    最近公司项目需求需要对设备在地图上面进行监控,并在当设备一定距离时进行聚合,这篇文章主要给大家介绍了关于uniapp实现地图点聚合功能的相关资料,需要的朋友可以参考下
    2022-12-12
  • 引入JavaScript时alert弹出框显示中文乱码问题

    引入JavaScript时alert弹出框显示中文乱码问题

    今天在HTML中引入JavaScript文件运行时,alert弹出的提示框中文显示为乱码,怎么解决此问题呢?下面小编给大家带来了引入JavaScript时alert弹出框显示中文乱码问题的解决方法,一起看看吧
    2017-09-09
  • uni-app入门页面布局之window和tabbar详解

    uni-app入门页面布局之window和tabbar详解

    每个页面按照结构可以分成三部分:window page tabbar.其中window和tabbar一般比较固定,page是平常业务开展的主要载体,根据业务需求进行页面配置。下面主要讲一下window和tabbar,感兴趣的朋友跟随小编一起看看吧
    2022-11-11
  • 捕获关闭窗口的脚本

    捕获关闭窗口的脚本

    对于需要获取一个窗口关闭后的返回信息时,需要用的到。
    2009-01-01
  • JavaScrip实现图片压缩与分辨率等比例缩放

    JavaScrip实现图片压缩与分辨率等比例缩放

    这篇文章主要为大家详细介绍了如何使用JavaScrip实现图片压缩与分辨率等比例缩放,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03

最新评论