# 阿里2021第一轮笔试
# 题一
一个半小时两道笔试题,题目如下:
# 1. 信号灯控制器
用 React 实现一个信号灯(交通灯)控制器,要求:
- 默认情况下, 1.1. 红灯亮20秒,并且最后5秒闪烁 1.2. 绿灯亮20秒,并且最后5秒闪烁 1.3. 黄灯亮10秒 1.4. 次序为 红-绿-黄-红-绿-黄
- 灯的个数、颜色、持续时间、闪烁时间、灯光次序都可配置,如: lights=[{color: '#fff', duration: 10000, twinkleDuration: 5000}, ... ]
import React from 'react'
import ReactDOM from 'react-dom
const trafficStyle = {
display: 'flex'
}
const itemStyle = {
width: '30px',
height: '30px',
border: '1px solid #000',
borderRadius: '15px',
margin: '5px',
listStyleType: 'none'
}
class Traffic extends React.Component {
timeId = null
constructor(props) {
super(props)
this.state = {
activeIndex: 0,
isLighting: false,
lights: [
{color: '#ff0000', duration: 10000, twinkleDuration: 5000},
{color: '#00ff00', duration: 10000, twinkleDuration: 5000},
{color: '#ffff00', duration: 10000, twinkleDuration: 0},
]
}
}
walk(index) {
if (index < 0 || index > this.state.lights.length - 1) {
index = 0
}
this.setState({
activeIndex: index
})
const current = this.state.lights[index]
if (current.duration > 0) {
this.shine(current.duration, () => {
if (current.twinkleDuration > 0) {
this.twinkle(current.twinkleDuration, () => {
this.walk(index + 1)
})
} else {
this.walk(index + 1)
}
})
}
if (current.duration <= 0 && current.twinkleDuration > 0) {
this.twinkle(current.twinkleDuration, () => {
this.walk(index + 1)
})
}
}
shine(duration, cb) {
this.setState({
isLighting: true
})
this.timeId = setTimeout(() => {
this.setState({
isLighting: false
})
cb()
}, duration)
}
twinkle(duration, cb) {
this.timeId = setTimeout(() => {
this.toggleLighting()
if (duration - 500 > 0) {
this.twinkle(duration - 500, cb)
} else {
cb()
}
}, duration > 500 ? 500 : duration)
}
toggleLighting() {
this.setState({
isLighting: !this.state.isLighting
})
}
componentDidMount() {
this.walk(this.state.activeIndex)
}
componentWillUnmount() {
clearTimeout(this.timeId)
}
render() {
const lightItems = this.state.lights.map((item, index) => {
return <Light key={index}
color={item.color}
isActive={index === this.state.activeIndex && this.state.isLighting} />
})
return (
<div className="traffic">
<ul className="traffic-lights" style={trafficStyle}>{lightItems}</ul>
</div>
)
}
}
function Light(props) {
return (
<li className='light'
style={{...itemStyle, backgroundColor: props.isActive ? props.color : '#fff'}}>
</li>
)
}
ReactDOM.render(<Traffic />, document.getElementById("root"));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 2. 寻找特定 IP
IPV4 的 IP 地址是32位的二进制数,为增强可读性,通常我们以8位为1组进行分割, 用十进制来表示每一部分,并用点号连接,譬如 192.168.1.1。显然,存在这样的 IP 地址, 0到9十个数字各出现一次。具备这样特征的 IP 地址里,表示成二进制数时,二进制数左右对称 (也就是“回文”,表示成32位二进制不省略0)的情况有几种,分别是哪些?要求性能尽可能高
# 题二
# 1.计算多个区间的交集
区间用长度为2的数字数组表示,如[2, 5]表示区间2到5(包括2和5);
区间不限定方向,如[5, 2]等同于[2, 5];
实现getIntersection 函数
可接收多个区间,并返回所有区间的交集(用区间表示),如空集用null表示
示例:
getIntersection([5, 2], [4, 9], [3, 6]); // [4, 5]
getIntersection([1, 7], [8, 9]); // null
function getIntersection() {
const nums = [...arguments];
const n = nums.length;
let ans = null;
let i = 1;
while (i < n) {
let section1 = ans !== null ? ans : nums[i-1].sort();
let section2 = nums[i].sort();
// 左边取大,右边取小
let left = Math.max(section1[0], section2[0]);
let right = Math.min(section1[1], section2[1]);
if (left <= right) {
ans = [left, right];
} else {
return null;
}
i++;
}
return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2. 计算dom元素的个数
DOM的体积过大会影响页面性能,假如你想在用户关闭页面时统计(计算并反馈给服务器) 当前页面中元素节点的数量总和、元素节点的最大嵌套深度以及最大子元素个数,请用 JS 配合 原生DOM API实现该需求(不用考虑陈旧浏览器以及在现代浏览器中的兼容性,可以使用任意 浏览器的最新特性;不用考虑shadow DOM)。比如在如下页面中运行后:
<html>
<head></head>
<body>
<div>
<span>f</span>
<span>o</span>
<span>o</span>
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
会输出:
{
totalElementsCount: 7,
maxDOMTreeDepth: 4,
maxChildrenCount: 3
}
1
2
3
4
5
2
3
4
5
# 3.实现一个Events模块
请使用原生代码实现一个Events模块,可以实现自定义事件的订阅、触发、移除功能
const fn1 = (... args)=>console.log('I want sleep1', ... args)
const fn2 = (... args)=>console.log('I want sleep2', ... args)
const event = new Events();
event.on('sleep', fn1, 1, 2, 3);
event.on('sleep', fn2, 1, 2, 3);
event.fire('sleep', 4, 5, 6);
// I want sleep1 1 2 3 4 5 6
// I want sleep2 1 2 3 4 5 6
event.off('sleep', fn1);
event.once('sleep', ()=>console.log('I want sleep));
event.fire('sleep');
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11