webDevInterviewQuestions/algorithm/02-array-string.md
2026-01-19 09:43:07 +08:00

167 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数组与字符串操作
## 1. 数组去重(多种方法)
> **场景**:标签列表去重、下拉选项去重、用户列表按 ID 去重、搜索历史去重。
> **解决**:数据列表中存在重复项影响展示或数据处理的问题。
```js
// 方法1: Set
const unique1 = arr => [...new Set(arr)];
// 方法2: filter + indexOf
const unique2 = arr => arr.filter((v, i) => arr.indexOf(v) === i);
// 方法3: reduce
const unique3 = arr => arr.reduce((acc, v) => acc.includes(v) ? acc : [...acc, v], []);
// 方法4: 对象数组按属性去重
const uniqueByKey = (arr, key) => {
const map = new Map();
arr.forEach(item => !map.has(item[key]) && map.set(item[key], item));
return [...map.values()];
};
```
## 2. 扁平化数组
> **场景**:多级分类菜单拍平为一维数组、树形结构转平铺列表、处理嵌套 JSON 数据。
> **解决**:嵌套数组不便于遍历、查找和渲染的问题。
```js
// 递归实现
function flatten(arr, depth = Infinity) {
return arr.reduce((acc, val) => {
return acc.concat(
Array.isArray(val) && depth > 0 ? flatten(val, depth - 1) : val
);
}, []);
}
// 迭代实现(使用栈)
function flattenIterative(arr) {
const stack = [...arr];
const result = [];
while (stack.length) {
const item = stack.pop();
Array.isArray(item) ? stack.push(...item) : result.unshift(item);
}
return result;
}
// 原生方法
arr.flat(Infinity);
```
## 3. 字符串反转
> **场景**:回文判断预处理、文本效果处理、简单加密/混淆。
> **解决**JS 没有内置字符串反转方法,需要手工实现。
```js
const reverse = str => str.split('').reverse().join('');
// 或者使用扩展运算符
const reverse2 = str => [...str].reverse().join('');
```
## 4. 判断回文
> **场景**:车牌号校验、特殊编码检测、文字游戏、算法题基础。
> **解决**:判断字符串正反读是否一致,常作为算法题输入校验或中间步骤。
```js
const isPalindrome = str => {
const clean = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return clean === clean.split('').reverse().join('');
};
// 双指针法
const isPalindrome2 = str => {
const s = str.toLowerCase().replace(/[^a-z0-9]/g, '');
let left = 0, right = s.length - 1;
while (left < right) {
if (s[left++] !== s[right--]) return false;
}
return true;
};
```
## 5. 最长公共前缀
> **场景**:搜索联想提取、路径匹配、文件名批量处理、自动补全功能。
> **解决**:批量字符串中提取共同前缀以进行分类或缩短展示。
```js
function longestCommonPrefix(strs) {
if (!strs.length) return '';
let prefix = strs[0];
for (let i = 1; i < strs.length; i++) {
while (strs[i].indexOf(prefix) !== 0) {
prefix = prefix.slice(0, -1);
if (!prefix) return '';
}
}
return prefix;
}
// 示例: ["flower","flow","flight"] => "fl"
```
## 6. 模板字符串解析
> **场景**:简易模板引擎、邮件/短信模板填充、国际化 i18n 文本替换。
> **解决**:将模板字符串中的占位符替换为实际数据,类似 Mustache/Handlebars 语法。
```js
function render(template, data) {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] !== undefined ? data[key] : match;
});
}
// 支持嵌套属性
function renderDeep(template, data) {
return template.replace(/\{\{(.+?)\}\}/g, (match, path) => {
const keys = path.trim().split('.');
let value = data;
for (const key of keys) {
value = value?.[key];
if (value === undefined) return match;
}
return value;
});
}
// 使用示例
render('Hello, {{name}}!', { name: 'World' }); // "Hello, World!"
renderDeep('{{user.info.name}}', { user: { info: { name: 'Tom' } } }); // "Tom"
```
## 7. 数组按属性去重并排序
> **场景**:用户列表按 ID 去重后按注册时间排序、商品列表按 SKU 去重后按价格排序。
> **解决**:对象数组的去重和排序组合操作,常见业务需求。
```js
function uniqueAndSort(arr, key, sortKey, order = 'asc') {
// 去重
const map = new Map();
arr.forEach(item => !map.has(item[key]) && map.set(item[key], item));
// 排序
return [...map.values()].sort((a, b) => {
return order === 'asc' ? a[sortKey] - b[sortKey] : b[sortKey] - a[sortKey];
});
}
// 示例
const users = [
{ id: 1, name: 'Tom', age: 20 },
{ id: 2, name: 'Jerry', age: 18 },
{ id: 1, name: 'Tom2', age: 25 }
];
uniqueAndSort(users, 'id', 'age'); // 按id去重按age升序排序
```