leetcode 最常见的前端基础算法面试题(下)
更多前端面试题点击这里获取哦
数学问题
加一
题目如下:
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
示例 3:
输入:digits = [0]
输出:[1]
这个题的关键有两点:
- 需要有一个进位的变量carry记录到底进位是几
- 还需要一个每次迭代都重置和的变量sum来帮我们算是否进位,以及进位后的数字
记住这个题,这是两数字相加的套路,这次是+1,其实就是两数相加的题(腾讯面试遇到过两数相加)
var plusOne = function(digits) {
let carry = 1; // 进位(因为我们确定+1,初始化进位就是1)
for(let i = digits.length - 1; i >= 0; i--){
let sum = 0; // 这个变量是用来每次循环计算进位和digits[i]的值的
sum = digits[i] + carry;
digits[i] = sum % 10; // 模运算取个位数
carry = (sum / 10) | 0; // 除以10是取百位数,并且|0表示舍弃小数位
}
if(digits[0] === 0) digits.unshift(carry);
return digits
};
x的平方根
题目如下:实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
由于返回类型是整数,小数部分将被舍去。
这道题是典型的二分法解题,所以我们需要熟悉二分法的通用模板,我们出一个题:
在 [1, 2, 3, 4, 5, 6] 中找到 4,若存在则返回下标,不存在返回-1
const arr = [1, 2, 3, 4, 5, 6];
function getIndex1(arr, key) {
let low = 0;
const high = arr.length - 1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
if (key === arr[mid]) {
return mid;
}
if (key > arr[mid]) {
low = mid + 1;
} else {
height = mid - 1;
}
}
return -1;
}
console.log(getIndex1(arr, 5)); // 4
所以这道题的意思就是,我们找一个数平方跟x最相近的数,二分法的用法中也有找相近数的功能
所以代码如下:
var mySqrt = function(x) {
let [l , r] = [0, x];
let ans = -1;
while(l <= r) {
const mid = (l + r) >> 1;
if(mid * mid > x){
r = mid - 1
} else if(mid * mid < x){
ans = mid; // 防止越界
l = mid + 1;
} else {
ans = mid;
return ans;
}
}
return ans;
};
};
Excel表序列号
这个题比较重要,也比较基础,简而言之就是进制转换,必须牢牢掌握
题目如下:
给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。
例如:
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
...
示例 1:
输入:columnNumber = 1
输出:"A"
示例 2:
输入:columnNumber = 28
输出:"AB"
示例 3:
输入:columnNumber = 701
输出:"ZY"
示例 4:
输入:columnNumber = 2147483647
输出:"FXSHRXW"
说白了,这就是一道26进制的问题,以前我们知道10进制转2进制就是不停的除2,把余数加起来,26进制也是一样,不停的除26
思路:
- 初始化结果 ans = 0,遍历时将每个字母与 A 做减法,因为 A 表示 1,所以减法后需要每个数加 1,计算其代表的数值 num = 字母 - ‘A’ + 1
- 因为有 26 个字母,所以相当于 26 进制,每 26 个数则向前进一位
- 所以每遍历一位则ans = ans * 26 + num
- 以 ZY 为例,Z 的值为 26,Y 的值为 25,则结果为 26 * 26 + 25=701
var titleToNumber = function(columnTitle) {
let ans = 0;
for(let i = 0; i < columnTitle.length; i++){
ans = ans * 26 + (columnTitle[i].charCodeAt() - 'A'.charCodeAt() + 1)
}
return ans;
};
阶乘中的零
题目:
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
这道题很简单,有多少个5就有多少个0,为什么这么说呢,我们分析一下题目
比如说 5!,
-
也就是 5 * 4 * 3 * 2 * 1 = 120,我们发现只有1个0,怎么产生的呢,主要造成者就是 2 * 5 构造了一个0
-
再看看10!
10! = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 其中,除了10 = 2 * 5和本身有一对2 * 5,所以有两个0,这样这道题的规律就出来了,我们再精进一步
如上图,每四个数字都会出现一个或者多个2的因子,但是只有每 5 个数字才能找到一个或多个5的因子。所以总体上看来,2的因子是远远多于5的因子的,所以我们只需要找5的倍数就可以了。
我们再进一步,按照上面的说法,我们需要计算比如10的阶乘有多少个0,要把10的阶乘算出来,其实我们只需要算10有几个5就好了,为什么呢
我们再进一步,按照上面的说法,我们需要计算比如10的阶乘有多少个0,要把10的阶乘算出来,其实我们只需要算10有几个5就好了,为什么呢
我们发现只有5的倍数的阶乘,才会产生5, 所以我们需要看看阶层数有多少个5,代码如下:
var trailingZeroes = function (n) {
let r = 0;
while (n > 1) {
n = Math.floor(n / 5);
r += n;
}
return r;
};
颠倒二进制位
题目如下:
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:
输入:11111111111111111111111111111101
输出:10111111111111111111111111111111
解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
因此返回 3221225471 其二进制表示形式为 10111111111111111111111111111111 。
这类题,就是翻转字符串,我们可以把其转为字符串,再转成数组,再reverse一下,这里我们选用数学的方式去解答,不用这种转字符串的方式。
解答这道题之前,我们需要了解的前置知识:
1.与预算 &
1 & 1 // 1的2进制最后一位是1,得到1
2 & 0 // 2的2进制最后一位是0,得到0
3 & 1 // 3的2进制最后一位是1,得到1
4 & 0 // 4的2进制最后一位是0,得到0
所以我们知道了怎么取10进制最后1位的2进制是几。
2.JavaScript 使用 32 位按位运算数(意思是我们的按位运算都会转成32位,你的数字不能超过32位,会出问题)
-
JavaScript 将数字存储为 64 位浮点数,但所有按位运算都以 32 位二进制数执行。
-
在执行位运算之前,JavaScript 将数字转换为 32 位有符号整数。
-
执行按位操作后,结果将转换回 64 位 JavaScript 数。
3.'<< 1' 运算
这个运算实际上就是把10进制乘以2,这个乘2在2进制上表现出右边填了一个0,我们距举例来说,
- 2的2进制是 10,2 << 1 得到4, 4的2进制是100,所以比10多了个0
- 3的2进制是 11,3 << 1 得到6。6的2进制是110,所以比11多了个0
以上就是规律
思路:循环取最后一位拼接起来即可
var reverseBits = function (n) {
let result = 0
for (let i = 0; i < 32; i++) {
result = (result << 1) + (n & 1)
n = n >> 1
}
// 为什么要 >>> 0 呢,一位javascript没有无符号整数,全是有符号的
// 不>>>0的话,得出来的值是负数,但是无符号整数是没有符号的
// javascript 有符号转化为无符号的方法就是>>>0
return result >>> 0
}
丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
进阶:
你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?
示例 1:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 2:
输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。
这题很简单,就是用0-n的总和减去数组总和
- 0 - n 的总和用等差数列:(首数+尾数)* 项数 / 2 来求
var missingNumber = function(nums) {
const len = nums.length
let sum = ((1 + len) * len) / 2
for (let i = 0; i < len; i++) {
sum -= nums[i]
}
return sum
}
的幂
题目如下:
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3的x次方
示例 1:
输入:n = 27
输出:true
示例 2:
输入:n = 0
输出:false
示例 3:
输入:n = 9
输出:true
思路
- 我们拿27来说:27 = 3 * 3 * 3,所以27是3的幂次方
- 我们拿29来说:29 = 3 * 3 * 3点几
也就是说,如果是3的幂次方,一直除以3,除到最后就等于1比如27/3/3/3等于1 如果不是3的幂次方,除到最后就是3点几/3 等于1点几
代码就出来了判断是不是等于1即可
var isPowerOfThree = function(n) {
while(n >= 3){
n /= 3;
}
return n === 1;
};
412. Fizz Buzz
这个题没啥好说的,就按照题目说的写代码就行,先看题目:
写一个程序,输出从 1 到 n 数字的字符串表示。
1.如果 n 是3的倍数,输出“Fizz”;
2.如果 n 是5的倍数,输出“Buzz”;
3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。
示例:
n = 15,
返回:
[
"1",
"2",
"Fizz",
"4",
"Buzz",
"Fizz",
"7",
"8",
"Fizz",
"Buzz",
"11",
"Fizz",
"13",
"14",
"FizzBuzz"
]
var fizzBuzz = function (n) {
const list = [];
for (let i = 1; i <= n; i++) {
const is3Times = i % 3 === 0; // 是否是3的倍数
const is5Times = i % 5 === 0; // 是否是5的倍数
const is15Times = is3Times && is5Times; // 是否是15的倍数
if (is15Times) {
list.push('FizzBuzz');
continue;
}
if (is3Times) {
list.push('Fizz');
continue;
}
if (is5Times) {
list.push('Buzz');
continue;
}
list.push(`${i}`);
}
return list;
};
环问题
这类问题的特点就是,你要循环寻找,到底怎么循环寻找,看题便知。
环形链表
题目如下:
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。否则,返回 false 。
输入:head = [3,2,0,-4], pos = 1
输出: true
解释: 链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出: true
解释: 链表中有一个环,其尾部连接到第一个节点。
我们采用标记法:
给遍历过的节点打记号,如果遍历过程中遇到有记号的说明已环
var hasCycle = function(head) {
let traversingNode = head;
while(traversingNode){
if(traversingNode.isVistitd) return true
traversingNode.isVistitd = true
traversingNode = traversingNode.next
}
return false;
};
202. 快乐数
题目如下:编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果 可以变为 1,那么这个数就是快乐数。
- 如果 n 是快乐数就返回 true ;不是,则返回 false 。
快乐数怎么分析呢?
我们来看一个表,就会得出结论,一个数按照快乐数定义的方式分别每个数字平方,会有两种情况
1.得到1
2.无限循环
无限循环参照下图
- 有人会说会不会一直变大,答案是不会:我们看下面列表,
可以看到如果你是13位,你的下一次快乐数算法会变为4位1053, - 如果你是9999, 4位,下一个快乐数是324
所以代码只要判断这两种就行了,代码如下:
// 封装获取快乐数的方法
function getNext(n){
n = String(n);
let sum = 0;
for(let num of n){
sum = sum + Math.pow(+num, 2);
}
return sum;
}
var isHappy = function(n) {
// 哈希表来看是否循环
const map = {};
while( n !== 1 ){
map[n] = true;
n = getNext(n)
if(map[n]) return false
}
return true
};
我还整理了一份前端面试题,包括人事、项目、小程序、HTML5/CSS3、JS、HTTP、ES6、Vue、REACT 等面试题,我们先一起看看题目。
人事+项目
这都是主观问题,列举出来的是可以参考下,人事面试也不能掉以轻心,有的公司人事是有一票否决权
小程序
- 数据请求怎么封装
- 参数传值的方法
- 提高小程序的应用速度的方法
- 小程序的优点
- 小程序的缺点
- 简述小程序原理
- 怎么解决异步请求问题
- 小程序和 Vue 写法的区别
- 小程序的双向绑定和 vue 哪里不一样
- 几种跳转,小程序内的页面跳转
HTML5\CSS3
- Doctype 作用? 严格模式与混杂模式-如何触发这两种模式,区分它们有何意义?
- 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?
- CSS 的盒子模型有几种?各有什么特点?
- link 和@import 的区别是?
- CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3 新增伪类有那些?
- 如何居中 div,如何居中一个浮动元素?
- 浏览器的内核分别是什么? 经常遇到的浏览器的兼容性有哪些?原因,解决方法是什么,常用 hack 的技
- css 属性那些有继承性?哪些没有?
- 如果盒子都为浮动,父类会没有高度,如何解决
- isibility 和 display 的隐藏有什么区别?
JS
- 原型/原型链/构造函数/实例/继承
- 如何实现 new 运算符
- 有几种方式可以实现继承
- arguments
- 数据类型判断
- 作用域链、闭包、作用域
- Ajax 的原生写法
- 对象深拷贝、浅拷贝
- 图片懒加载、预加载
- 实现页面加载进度条
React
- 区分 Real DOM 和 Virtual DOM
- React 有什么特点?
- 列出 React 的一些主要优点。
- React 有哪些限制?
- 什么是 JSX?
- 你了解 Virtual DOM 吗?解释一下它的工作原理。
- 为什么浏览器无法读取 JSX?
- 与 ES5 相比,React 的 ES6 语法有何不同?
- 怎样解释 React 中 render() 的目的。
完整版的2021前端面试题精编PDF文档点击这里获取,还有面试题没有列举出来,小伙伴们到时可以好好看面试题。
如果看了觉得有帮助的,欢迎 点赞 关注 评论
个人微信号(添加请备注“焖豆”)
往期文章