大厂面试高频题解析:从 CSS 绘制多种图形到斐波那契数列的三种实现
在技术面试中,我们常常会遇到两类看似简单却暗藏玄机的问题:一类是前端基础能力考察(比如用纯 CSS 画各种图形),另一类则是算法思维与代码优化(比如经典的斐波那契数列)。本文将结合实际代码,带你一步步深入理解这些“小题”背后的“大智慧”。
一、CSS 篇:利用 CSS 绘制多种几何图形
原理简述
在 Web 开发中,利用 CSS 来绘制几何图形是一项基本技能。它不仅能展示你的创意,还能体现你对 CSS 布局和渲染机制的理解。
1. 三角形
.triangle {
/* 三角形 */
width: 5px;
height: 5px;
border: 10px solid transparent;
border-top-color: #f00;
/* 注释掉的其他边框颜色设置 */
/* border-top: 100px solid #f00;
border-left: 100px solid #0f0;
border-right: 100px solid #00f;
border-bottom: 100px solid #ff0; */
}
- 解释:通过设置元素的宽高为
0并使用不同方向的border属性来创建三角形。在这个例子中,我们仅设置了顶部边框的颜色,其余边框为透明,从而形成一个向上的红色三角形。
2. 扇形
.sector{
width: 100px;
height: 100px;
border-radius: 100px 0 0;
background-color: #00f;
/* transform: rotate(45deg); */
}
- 解释:通过设置特定的
border-radius来创建扇形。这里我们将左上角的圆角半径设置为100px,而其他三个角保持直角,背景色设为蓝色。
3. 另一种扇形
.sector2{
border: 100px solid transparent;
width: 0;
border-radius: 100px;
border-top-color: #f00;
}
- 解释:这种方法利用了
border-radius和border的特性来创建扇形。这里通过设置border-top-color为红色,其他边框透明,再应用border-radius创建圆形效果的一部分。
4. 箭头
.arrow{
width: 10px;
height: 10px;
border: 1px solid #000;
border-bottom-color: transparent;
border-left-color: transparent;
transform: rotate(45deg);
}
- 解释:箭头是通过设置矩形的两个边框为透明,并旋转45度来实现的。这种方法可以用来创建简单的箭头图标。
5. 椭圆
.oval{
width: 100px;
height: 50px;
border-radius: 50px / 25px;
background-color: #ff0;
}
- 解释:椭圆可以通过设置不同的宽度和高度以及
border-radius的比例来获得。这里的border-radius设置为50px / 25px,意味着水平方向的半径是50px,垂直方向的半径是25px,从而形成了一个黄色的椭圆。
效果总览:
二、算法篇:斐波那契数列的三种实现方式
斐波那契数列(Fibonacci Sequence)定义如下:
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2) (n ≥ 2)
这道题看似简单,却是考察 递归、时间复杂度、空间换时间、闭包 等核心概念的绝佳载体。下面我们将从最朴素的实现,逐步优化到工业级写法。
1️⃣ 普通递归:简洁但低效(指数级时间)
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
console.log(fib(10)); // 55
✅ 优点:代码简洁,逻辑清晰,符合数学定义。
❌ 缺点:存在大量重复计算。例如 fib(5) 会多次计算 fib(3)、fib(2) 等。
- 时间复杂度:O(2ⁿ) —— 指数爆炸!
- 空间复杂度:O(n) —— 递归栈深度。
🚫 在实际工程或面试中,这种写法通常会被面试官追问:“能优化吗?”
2️⃣ 记忆化搜索(Memoization):用空间换时间
const cache = {};
function fib(n) {
if (n in cache) return cache[n];
if (n <= 1) return n;
cache[n] = fib(n - 1) + fib(n - 2);
return cache[n];
}
console.log(fib(10)); // 55
✅ 优点:
- 每个
fib(k)只计算一次,后续直接查表。 - 时间复杂度降为 O(n) ,空间复杂度 O(n)。
❌ 缺点:
cache是全局变量,容易被外部污染或误改。- 不利于模块化和封装。
💡 这就是典型的“空间换时间”思想,在动态规划中广泛应用。
3️⃣ 闭包 + IIFE:封装记忆化逻辑,避免全局污染
const fib = (function () {
const cache = {}; // 私有变量,外部无法访问
return function (n) {
if (n <= 1) return n;
if (cache[n]) return cache[n];
return cache[n] = fib(n - 1) + fib(n - 2);
};
})();
✅ 优点:
- 利用 立即执行函数表达式(IIFE) 创建闭包,
cache成为私有状态。 - 外部只能通过
fib(n)调用,无法直接操作缓存。 - 保持了记忆化的高效性,同时提升了代码的健壮性和可维护性。
🔍 这正是大厂面试官想看到的:不仅会写算法,还懂得工程化思维和封装意识。
总结:小图形见功底,小递归见思维
前端面试中的“简单题”,往往藏着最真实的考察意图:
-
CSS 图形题(如三角形、扇形、箭头)
不是让你炫技,而是检验你对 盒模型、border 渲染机制、border-radius 非对称用法、transform 坐标变换 的理解深度。能用纯 CSS 实现复杂形状,说明你真正“看见”了浏览器如何绘制像素。 -
斐波那契数列
表面是算法,实则考察三层能力:- 基础编码能力(能否写出正确递归)
- 性能敏感度(是否意识到重复计算问题)
- 工程素养(能否用闭包封装状态,避免污染全局)
| 方案 | 时间复杂度 | 空间复杂度 | 推荐度 | 考察重点 |
|---|---|---|---|---|
| 普通递归 | O(2ⁿ) | O(n) | ❌ | 递归理解 |
| 全局缓存记忆化 | O(n) | O(n) | ⚠️ | 动态规划思想 |
| 闭包 + IIFE 封装 | O(n) | O(n) | ✅ | 模块化 + 数据私有化意识 |
💡 真正拉开差距的,从来不是“会不会”,而是“好不好” 。
能写出第一版是合格,能优化到第三版,才是大厂想要的候选人。