携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 2 天,点击查看活动详情
在上一篇文章中,我们通过两种不同的思路实现了旋转数组,还记得我们在最后留的那个问题吗?那么这两种解题思路,到底哪种更优呢?
复杂度分析
如果我们需要比较某个算法的差异性,那就不得不提一下算法的复杂度了,而算法的复杂度又分为时间复杂度和空间复杂度,如果对算法复杂度还不太了解的童鞋,可以在掘金上搜一下关于算法复杂度的文章。关于时间复杂度和空间复杂度的描述,我们可以阅读这篇文章,而下面的图就恰恰为我们说明了随着时间或空间的变化数值跟着不断变化的趋势。
首先我们分析一下第一种解题思路的复杂度,如果不记得第一种解题思路的,可以点这里回顾一下之前的解题思路。
在思路一中,我们通过for循环来遍历这个数组,所以思路一的时间复杂度应该是O(n),但我们在循环的内部使用了数组的unshift方法来对数组进行操作,而数组本身是一个有序的数据结构,如果从数组末尾取出一个值,然后插入到数组的首位,其实这个操作是非常慢的。就好比我们要从一个队伍的最末尾拉一个人出来,然后塞到队伍的最前面,那么整个队伍的排序就都需要往后移动一位,因此unshift操作实际上是非常慢的,而它的时间复杂度也是O(n),所以思路一的整体时间复杂度是O(n^2),空间复杂度是O(1),因为我们并没有设置多余的数组来存储内容。
在思路二中,我们并没有对数组进行遍历,因此思路二中的时间复杂度是O(1),而空间复杂度是O(n),为什么空间复杂度是O(n)呢?因为我们在思路二中将数组进行了拆分,通过数组的slice方法,而slice方法本身是不会改变原数组的,因此slice的操作其实是很快的。
前端本身的算法就是重时间而轻空间,因为我们需要及时的计算获取返回值,哪怕我们多使用一些变量(多占用一些内存空间),其实也是没有什么关系的,因此思路二的实现要比思路一的实现要更优一些。当然我们光说是没有用的,实际还是需要做相关的性能测试才能证明这点,下面我们就一起来完成性能测试。
性能测试
两种实现方式,我们使用相同的数据来进行测试,假设有一个数组,它里面有10W个元素,我们需要反转9W个元素,下面我们一起来实现一下相关的代码。
// 性能测试
const arr1 = [];
for (let i = 0; i < 10 * 10000; i++) {
arr1.push(i);
}
console.time('rotate1');
rotate1(arr1, 9 * 10000);
console.timeEnd('rotate1');
const arr2 = [];
for (let i = 0; i < 10 * 10000; i++) {
arr2.push(i);
}
console.time('rotate2');
rotate2(arr2, 9 * 10000);
console.timeEnd('rotate2');
上述代码在浏览器的控制台中可以明显的看出思路一的执行时间是思路二的八百多倍,这足以说明思路一的执行效率有多低,如果我们在面试的过程中能够写出相关的思路,并且讲明白它们之间的区别是为什么,那么这个题目你就彻底的吃透了,相信面试官也会对你的回答非常满意。
结尾
这篇文章是对上一篇文章剩余部分的补充,因此实际的内容不多,只是补充一些概念性的内容,但是我们还是需要做到知其然知其所以然,不能光知道怎么解答这个问题,还要知道它的实现思路,以及为什么这么实现,这样才能做到彻底吃透这个算法题,下次再遇到才能从容不迫的去解答。
学习算法光靠死记硬背也不行,还是需要通过一定的技巧和思路来学习,这样才不会陷入学了忘忘了学的地步,让我们一起加油吧!
如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家