前言
上个月面试的时候,面试官问了这样一道算法题:给定一个有序数组,数组里有重复元素,要求原地操作数组,删除重复元素。
input: [0, 0, 1]
output: [0, 1]
input: [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
output: [0, 1, 2, 3, 4]
当时第一反应不就是数组去重嘛,[...new Set(arr)] 一句代码的事,显然这不是面试官想考察的内容,于是我又接着反应,是不是可以遍历一遍数组,找到重复元素,然后使用 splice 方法删掉?面试官说了一句要原地修改数组,你再想想有没别的方法。这也不行,那也不行,也不能开辟一个新数组来筛选,一时间沉默寡言,说不出个所以然来,当时一直想着「原地修改」这几个字,那种情境下,越想越陷进去,最后只好说不会。
思路
回去之后想了下,哎呀,还是不够熟练的缘故,反应不过来,只需要做个数据交换就可以了呀。思路是这样子的:要求是不能申请新空间,得在原数组上操作,那可以设置一个 temp 变量,用来临时存储每一个不重复的数,假设数组中第一个元素为 temp,设置变量 len 为 1(因为第0个元素就是不重复的),for 循环从第二个元素开始与 temp 做比较,如果相等,就把 for 循环里的 i 加一,忽略重复的元素,这样直到不想等的时候,就把 i 指向的元素与 arr[len] 做交换,这样就做到了把不重复元素搬了过来;最后 len++ ,继续去找下一个不重复元素赋值,遍历完后就能得到结果。比如 [0,0,1,1,2] 那么第一次操作后就是 [0,1,1,1,2] ,把重复元素 0 干掉了,因为数组是有序的,时间复杂度是 O(n) ,空间复杂度为 O(1)。
实现
代码实现如下:
function uniqArr(arr){
var temp = arr[0];
var len = 1;
for(var i = len; i < arr.length; i++){
if(arr[i] !== temp){
arr[len] = arr[i];
temp = arr[i];
len++;
}
}
// 去重后,把后面多余的数据删掉
arr.splice(len)
// 原地修改,不返回结果
}
// Test
var arr = [0,0,1,1,1,2,2,3,3,4]
uniqArr(arr)
console.log(arr) // [0, 1, 2, 3, 4]
总结
平时还是要多练习,多写代码,多想想有没其它的解决方式,有时候一道题,你会两种解法,但恰恰别人是想考第三种解法,那就没办法,一时想不出来也还是自己知识欠缺,是自己的问题。
Keep coding.
(完)