携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
现在市面上前端面试考察到算法的公司越来越多,并不是因为做前端的人多了,所以面试越来越卷,恰恰说明了前端能做的工作也越来越多。
最初算法只有后端人员面试时才会考察,而现在前端也需要算法,足以说明这一点。一个懂算法的前端与不懂算法的前端,他们的思维方式及代码的编写都可能会大大的不同,因此作为一个有追求的前端,我们还是需要好好的学习一下算法,哪怕只是为了在面试中让自己更加的出彩也是值得的。
虽然大家都知道算法是加分项,但是很多人对算法'望而生畏',一遇到算法题就打退堂鼓,总觉得算法很难,其实我们只要掌握了相应的方法,那么算法学起来其实并没有那么困难。
今天我们就先从一道简单的算法题开始,让我们一步一步走入算法的怀抱。因为是第一道题,所以我们用初探这个词来形容,高手可以略过。
这是在leetcode上的第189道题,具体的提纲描述可以看这里,大致如下:
给你一个数组,将数组中的元素向右轮转 `k` 个位置,其中 `k` 是非负数。
简单描述如下:
1. 输入一个数组 [1, 2, 3, 4, 5, 6, 7]
2. k = 2, 即旋转 2 步
3. 输出 [6, 7, 1, 2, 3, 4, 5]
旋转数组的意思就是,将数组中的最后一位往前移动,移动的次数就是这个k值,因此第一步的我们需要将数组中的7移动到第一位,我们得到的结果就是[7, 1, 2, 3, 4, 5, 6],然后因为k值是2,所以我们还需要往前再移动一次,因此最终得到的结果就是上面看到的[6, 7, 1, 2, 3, 4, 5],这里只是大概描述这个题目的意思,那么接下来我们需要开始分析如何编写相关的代码,并得到最终我们需要的结果。
思路分析
首先当我们拿到这个题目的时候,我们第一时间应该想到的就是数组的基本操作,如果对数组的基本操作还不熟悉的童鞋,可以看这里。
下面我们提供两种结题思路:
思路一:首先通过pop把数组末尾的元素挨个弹出,然后通过unshift将弹出的内容添加到数组的前面;
思路二:将数组进行拆分,然后通过concat将拆分出来的数组拼接到一起。
上面我们只是通过文字将简单的思路描述了一下,那么接下来我们开始代码的实战演练,这里我使用ts来进行编写,还有对ts不了解的童鞋,可以在掘金上搜一下ts相关的文章,相信会让你很快上手,并彻底爱上它的。
代码演练
思路一实现,代码如下:
/*
* 旋转数组 K 步,使用 pop 和 unshift
* @param arr number[]
* @param k number
* @returns arr number[]
*/
const rotate1 = (arr: number[], k: number): number[] => {
// 获取数组的长度
const len = arr.length;
// 如果旋转的k值不存在,或者数组的长度为0,则直接返回该数组
if (!k || len === 0) return arr;
// 获取余数的绝对值,防止k大于数组的长度
const step = Math.abs(k % len);
// 时间复杂度 O(n^2)
for (let i = 0; i < step; i++) {
const last = arr.pop();
if (last != null) {
arr.unshift(last); // 数据是有序结构,unshift 操作数字非常慢!O(n)
}
}
return arr;
}
// 测试
const arr = [1, 2, 3, 4, 5, 6, 7];
const arr1 = rotate1(arr, 2);
console.log(arr1); // [6, 7, 1, 2, 3, 4, 5]
思路二实现,代码如下:
/*
* 旋转数组 K 步,使用 concat
* @param arr number[]
* @param k number
* @returns arr number[]
*/
const rotate2 = (arr: number[], k: number): number[] => {
// 获取数组的长度
const len = arr.length;
// 如果旋转的k值不存在,或者数组的长度为0,则直接返回该数组
if (!k || len === 0) return arr;
// 获取余数的绝对值,防止k大于数组的长度
const step = Math.abs(k % len);
// 取出数组最后的内容,负的值是从数组最后面开始截取
const part1 = arr.slice(-step);
// 从第0位开始,截取剩余的长度,因为上一步已经把数据某位的数字取出来了,所以这里只需要取还剩余的内容即可
const part2 = arr.slice(0, len - step);
// 合并数组
const part3 = part1.concat(part2);
return part3;
}
// 测试
const arr = [1, 2, 3, 4, 5, 6, 7];
const arr2 = rotate2(arr, 2);
console.log(arr2); // [6, 7, 1, 2, 3, 4, 5]
思考一下🤔,虽然我们在上面通过两种方式实现了旋转数组,并最终得到了我们想要的答案,但是这两种实现方法到底哪种方式更优呢?下一节我们在一起来分析。
结尾
这里我们虽然给出了相应的解答方式,但是我们还没有给大家分析出这两种实现方式的差异,这一节就先到这里了,下一节我们再一起来分析这两种解题方式的差异性,如果你也是个算法小白,那么我们一起来学习把,相信自己的付出一定会有回报的,感谢大家的支持。
如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家