# 🔥 数组去重:从双重循环到 Set,面试官想听什么?

🔥 数组去重:从双重循环到 Set,面试官想听什么?

手写 unique 是大厂面试的高频题,但仅仅写出来不够。

本文带你逐层优化 ,分析时间/空间复杂度,写出让面试官眼前一亮的代码。

一、题目与基础要求

js 复制代码
// 输入
[1, 2, 3, 2, 5]
// 输出
[1, 2, 3, 5]

最基本的得分点

  • 函数命名清晰(unique
  • 参数校验(Array.isArray
  • 写注释(函数功能、参数、返回值、作者、日期)

二、方法一:双重循环(O(n²))

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  if (arr.length === 0) return [];
  
  const res = [arr[0]];
  for (let i = 1; i < arr.length; i++) {
    let duplicate = false;
    for (let j = 0; j < res.length; j++) {
      if (arr[i] === res[j]) {
        duplicate = true;
        break;
      }
    }
    if (!duplicate) res.push(arr[i]);
  }
  return res;
}

复杂度 :时间 O(n²) | 空间 O(n)
优点 :兼容性好,思路简单
缺点:大数据量性能差

三、方法二:indexOf + 新数组(O(n²))

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  const res = [];
  for (let i = 0; i < arr.length; i++) {
    if (res.indexOf(arr[i]) === -1) {
      res.push(arr[i]);
    }
  }
  return res;
}

indexOf 内部也是循环,所以仍然是 O(n²),但代码更简洁。

四、方法三:filter + indexOf(函数式编程)

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  return arr.filter((item, index) => arr.indexOf(item) === index);
}

原理indexOf 总是返回第一次出现的位置,只有当前下标等于第一次出现位置时才保留。

⚠️ 注意NaN 去重会失效(因为 NaN !== NaN),但面试时可以主动提出来,体现你的知识深度。

五、方法四:先排序再去重(O(n log n))

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  const sorted = [...arr].sort();  // 拷贝后排序,不改变原数组
  const res = [sorted[0]];
  for (let i = 1; i < sorted.length; i++) {
    if (sorted[i] !== sorted[i - 1]) {
      res.push(sorted[i]);
    }
  }
  return res;
}

复杂度 :排序 O(n log n) + 遍历 O(n) → O(n log n)
注意:必须拷贝原数组,避免副作用。

六、方法五:对象字面量(空间换时间,O(n))

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  const res = [];
  const seen = {};
  for (let i = 0; i < arr.length; i++) {
    const item = arr[i];
    if (!seen[item]) {
      res.push(item);
      seen[item] = 1;
    }
  }
  return res;
}

复杂度 :时间 O(n) | 空间 O(n)
缺点 :对象 key 只能是字符串,1'1' 会被视为相同。
改进 :使用 Map(ES6),可以区分类型。

js 复制代码
// 使用 Map 修复类型区分问题
function unique(arr) {
  const map = new Map();
  const res = [];
  for (const item of arr) {
    if (!map.has(item)) {
      map.set(item, true);
      res.push(item);
    }
  }
  return res;
}

七、方法六:Set(最优解,ES6)

js 复制代码
function unique(arr) {
  if (!Array.isArray(arr)) return [];
  return [...new Set(arr)];
}

为什么最强?

  • 时间复杂度 O(n)
  • 代码极简
  • 正确处理 NaNundefinednull
  • Set 内部基于哈希表,性能稳定

八、面试加分项:时间/空间复杂度对比表

方法 时间复杂度 空间复杂度 是否改变原数组 推荐度
双重循环 O(n²) O(n)
indexOf O(n²) O(n) ⭐⭐
filter + indexOf O(n²) O(n) ⭐⭐
排序后去重 O(n log n) O(n) 需拷贝避免 ⭐⭐⭐
对象 / Map O(n) O(n) ⭐⭐⭐⭐
Set O(n) O(n) ⭐⭐⭐⭐⭐

九、完整代码(带注释 + 健壮性)

js 复制代码
/**
 * 数组去重(使用 Set)
 * @param {Array} arr - 输入数组
 * @returns {Array} - 去重后的新数组
 * @author kisshyshy
 * @date 2026-05-28
 */
function unique(arr) {
  // 参数校验:必须是数组
  if (!Array.isArray(arr)) {
    console.error('unique 的参数必须是数组');
    return [];
  }
  // 边界处理:空数组直接返回
  if (arr.length === 0) return [];
  
  // 核心:Set 自动去重,再转为数组
  return [...new Set(arr)];
}

// 测试
console.log(unique([1, 2, 3, 2, 5]));        // [1,2,3,5]
console.log(unique([NaN, NaN, 1]));           // [NaN,1]
console.log(unique([]));                      // []
console.log(unique('string'));                // [] + 错误提示

十、总结

大厂面试手写 unique不要只给一个答案。正确的流程是:

  1. 先写参数校验、边界处理
  2. 给出一种最直观的方法(如双重循环)并分析复杂度
  3. 逐步优化,引出 indexOffilter、排序法
  4. 最终给出 Set 最优解,并解释为什么它最好
  5. 主动提一下 NaN 去重的问题和 Map 的改进

这样,你展现的不仅是代码能力,更是算法思维、工程素养和沟通能力


💬 评论区聊聊:你第一次写数组去重用的是哪种方法?踩过哪些坑?

本文作者:kisshyshy
一个热爱分享底层技术与工程实践的 AI 全栈开发者

相关推荐
swipe34 分钟前
做多轮对话 Agent,为什么我建议把短期记忆放到 Redis
后端·面试·llm
2301_7736436235 分钟前
ceph镜像
前端·javascript·ceph
To_OC1 小时前
万字解析《JS语言精粹》之第四章:函数15大核心精髓(JS灵魂核心)
前端·javascript·代码规范
宋拾壹1 小时前
同时添加多个类目
android·开发语言·javascript
IT知识分享1 小时前
从零开发在线简繁转换工具:OpenCC 实战、避坑经验与方案选型
javascript·python
swipe1 小时前
别再把关系库和向量库拆开了:PostgreSQL 搭建 AI 长期记忆层实战
面试·langchain·llm
川冰ICE1 小时前
JavaScript实战④|天气查询应用,调用API与异步处理
javascript·css·css3
微扬嘴角1 小时前
react篇4--setState、LazyLoad和Hooks
前端·javascript·react.js
杨梦馨1 小时前
万级数据表格卡死?Web Worker 一招搞定
前端·javascript·vue.js
用户484526255821 小时前
JavaScript 数组不是数组,是对象
javascript