持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
前言
手写代码可以训练我们的解题思路,同时也能够提高我们平时工作的效率;一开始总是想定个小目标:每天一个手写代码,但是无奈平时工作很多,又把目标改成每周,然而还是难以坚持,然后就每年把;每年一个手写代码,也算是一个年度总结,这个目标也不难实现;
题目
const arr = [[1, 2, 2],[3, 4, 5, 5],[6, 7, 8, 9, [11, 12, [12, 13, [14]]]],10] 编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
网友实现的题解
由于数组扁平化可以直接使用API flat,数组去重可以使用Set,数组排序可以使用sort实现,于是网友写出来一个简洁的版本:
Array.prototype.flatten = function () {
return Array.from(new Set(this.flat(Infinity))).sort((a, b) => a - b)
}
但是这样写未免太简单,而且如果碰到面试问这个问题,面试官肯定会再问一句:还有其他方法吗?这个时候就很有可能束手无策了
我们从上面这个题解看出来这道题考察了数组扁平化、数组去重和数组排序,也就是我们需要自己去实现sort、flat还有去重
实现Array.prototype.flat
reduce + concat
先实现一个简单的展开:[12, 13, [14]]
可以使用concat展开一层
arr.reduce((acc, val) => acc.concat(val), [])
// 或者
[].concat(...arr)
那么假设数组的层级为d,我们每展开一层,d-1,直到d=0
function flatDeep(arr, d = 1) {
return d > 0
? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
: arr.slice();
}
复杂度分析:这个方法的复杂度跟最深的一个数组项有关,假设最深的数组项每一项长度为a1...an,那么复杂度为O(na1a2...*an),可以看到复杂度非常高,因为我们这里使用了递归,这里我们也可以转为循环,但是复杂度不变,所以我们目前不去展示如何转换为循环
数组的栈方法
注意:这种方法只能展开一级
function flatten(input){
// 先浅拷贝一份数据
const stack = [...input]
const res = []
// 遍历这个数组
while(stack.length>0){
const item = stack.pop()
if(Array.isArray(item)){
stack.push(...item)
} else {
res.push(item)
}
}
return res.reverse()
}
假设每一个数组项有an个元素,那么展开一级的复杂度为:O(len(a1)+...+len(an))
借助生成器函数
function* flatDeep(arr, d=1) {
for (const item of arr) {
if (Array.isArray(item) && d > 0) {
yield* flatDeep(item, d - 1)
} else {
yield item
}
}
}
该方法的复杂度和第一种方法相同
去重和排序
去重和排序我们选择先去重再排序
由于这里是简单数据类型,那么我们就就借助对象去实现去重(这是我工作中常用的一个方法);排序则有多种方式:快速排序、插入排序、希尔排序、桶排序,我们选择比较简单的快速排序
function uniqueAndSort(arr) {
const temp = {}
const len = arr.length
const res = []
for (var i = len - 1; i >= 0; i--) {
const element = arr[i]
if (!temp[element]) {
temp[element] = 1
res.unshift(element);
}
}
function quickSort(iArr) {
var n = iArr.length;
// 若只有一个,则返回
if (n <= 1) {
return iArr;
}// 若有多个,则选择基准进行分组,递归处理
else {
var p = parseInt(n - 1);
var pivot = iArr[p];
var leftArr = [], rightArr = [], arrVal;
for (var i = 0; i < n - 1; i++) {
arrVal = iArr[i];
if (arrVal <= pivot) {
// 小于基准放置左侧
leftArr.push(arrVal);
} else {
// 大于基准放置右侧
rightArr.push(arrVal);
}
}
// 递归计算左边、右边子集,将数组合并返回
return quickSort(leftArr).concat([pivot].concat(quickSort(rightArr)));
}
}
return quickSort(res);
}
总结
我们用了三种方式去实现flat,用了一种常用的方式去实现去重和排序,以后遇到这个题应该不会再像“网友”那样只能给出一个孤零零的答案了