记录--如何判断两个数组的内容是否相等
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
题目
给定两个数组,判断两数组内容是否相等。
- 不使用排序
- 不考虑元素位置
例:
1 2 | [1, 2, 3] 和 [1, 3, 2] // true [1, 2, 3] 和 [1, 2, 4] // false |
思考几秒:有了😀😀
1. 直接遍历✍
- 直接遍历第一个数组,并判断是否存在于在第二个数组中
- 求差集, 如果差集数组有长度,也说明两数组不等(个人感觉比上面的麻烦就不举例了)
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 会有问题
1 2 3 4 5 6 7 8 9 10 11 | 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
1 2 3 4 5 6 7 8 9 10 11 | 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了,如果数组元素有重复呢?
1 2 3 4 5 6 7 | // 重复的元素都是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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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. 统计元素次数(最终方案)✍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 就等于不匹配
这样就不需要俩个对象了,而且第二个遍历的时候如果找不到这个值的话也可以直接退出了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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. 评论区大佬方案(操作第二个数组)👍
遍历第一个数组,在第二个数组找到就删除第二个数组中对应的元素,没有找到直接不等,最后再判断一下第二个数组的长度即可。实际使用中一般不直接操作原数组,浅复制一下就好
可能没有前几个性能好,但是想法还是很好的点赞~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 } |
注意事项
这个题需要注意:
- 先判断长度,长度不等 必然不等
- 元素可重复
- 边界情况考虑
- '1' 和 1 (Object的key是字符串, Map的key没有限制)
- NaN
- null undefined
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2022-10-19 记录--有关CSS盒模型之内边距、边框、外边距的十九问题