2021腾讯校招前端第二次笔试题总结
2021
腾讯校招前端第二次笔试题总结
两个有序的数组合并成一个 🔗
这题就是我上面说的能 ac100%,但是因为粗心只 ac 了 60%…。
原因就是腾讯的笔试题都是采用的标准输入输出。
所有的输入数据都要手动的处理成我们想要的样子。
V8 的输入输出就是readline
(读取一行)和print
(打印一行)。
这题给的样例输入输出如下(没记错应该是这个样例)。
输入:
1,2,4
1,3,4
输出:
1,1,2,3,4,4
也就是读取两行,转成数组再操作。
可是我傻逼了,用了split(',')
之后忘记转成数字了…
这就导致了算法没错,但是比较的结果出错了。
"3" > "122"; // true
3 > 122; // false
整体的算法如下(这个就是归并排序中每一次合并的一个算法)。
这题应该考察双指针的知识点吧。
function merge(arr1, arr2) {
let i = 0;
let j = 0;
let k = 0;
const result = [];
while (i < arr1.length && j < arr2.length) {
if (arr1[i] < arr2[j]) {
result.push(arr1[i]);
i++;
} else {
result.push(arr2[j]);
j++;
}
k++;
}
// 这里防止两个数组有一个没遍历完成,要直接把剩下的元素push的结果集的末尾
if (i < arr1.length) {
for (k = i; k < arr1.length; k++) {
result.push(arr1[k]);
}
} else {
for (k = j; k < arr2.length; k++) {
result.push(arr2[k]);
}
}
return result;
}
const arr1 = readline()
.split(",")
.map((s) => Number.parseInt(s));
const arr2 = readline()
.split(",")
.map((s) => Number.parseInt(s));
const result = merge(arr1, arr2);
print(result.join(","));
写到中间想起来没转成数字这件事,写着写着又给忘了…
JSON
的扁平化 🔗
题意大致就是有一个对象,每秒会记录当时的点击量。
要求给你一个这个对象的json
格式,转成数组形式。
输入:
{ "1": 123, "2": 234, "8": 7 }
输出:
[123, 234, 0, 0, 0, 0, 0, 7]
这题很快就ac
了还是相当开心的。
function fn(str) {
const obj = JSON.parse(str);
const result = [];
// 得到所有的key,也就是所有的秒数
Object.keys(obj).forEach((item) => {
const i = Number.parseInt(item);
if (i > 0 && i <= Number.MAX_SAFE_INTEGER) {
// 索引为秒数 - 1
result[i - 1] = obj[i];
}
});
for (let i = 0; i < result.length; i++) {
// 找空位,以0代替
if (result[i] === undefined) {
result[i] = 0;
}
}
return result;
}
const str = readline();
const result = fn(str);
// json形式输出
print("[" + result.join(",") + "]");
计算中位数 🔗
给定一个长度为n
(n
为偶数)的数组,问如果删除每一位之后,剩下的n - 1
位的数组中位数是多少。
输入:
6
1 2 3 4 5 6
输出
4 // 删除1之后,剩下的数组中位数为4
4 // 删除2之后,剩下的数组中位数为4
4 // 删除3之后,剩下的数组中位数为4
3 // 删除4之后,剩下的数组中位数为3
3 // 删除5之后,剩下的数组中位数为3
3 // 删除6之后,剩下的数组中位数为3
这题我觉得我思路应该是没错的。
思路就是我们要先保存原来的索引,然后对这个数组进行排序。
由于数组的长度是偶数,我们可以知道。
如果删除了前 n / 2
个数中的某一个,那么中位数一定是第 n / 2 + 1
个。
如果删除了后 n / 2
个数中的某一个,那么中位数一定是第 n / 2
个。
可以以他的样例1 2 3 4 5 6
。
如果删除了3
前面的任意一个数,包括3
,那么中位数就会落到4
这个数字上。
2 3 4 5 6
1 3 4 5 6
1 2 4 5 6
如果删除了4
后面的任意一个数,包括4
,那么中位数就会落到3
这个数字上。
1 2 3 5 6
1 2 3 4 6
1 2 3 4 5
理解上面之后就可以写代码了。
function fn(n, arr) {
// 保存每个数字原来位置的索引
// 这里要注意原题目并没有说数组不重复,所以存一个索引数组
const map = {};
for (let i = 0; i < arr.length; i++) {
if (map[arr[i]] === undefined) {
map[arr[i]] = [i];
} else {
map[arr[i]].push(i);
}
}
// 排序,开始求中位数
arr.sort();
// 右中位数的索引
const rightMid = n / 2;
// 左中位数的索引
const leftMid = rightMid - 1;
// 两者对应的值
const rightMidVal = arr[rightMid];
const leftMidVal = arr[leftMid];
const result = [];
// 删除[0, leftMid]索引中的其中一个值,剩下的中位数一定是rightMidVal
for (let j = 0; j <= leftMid; j++) {
// 得到这个数原来对应的索引位置
const indexArr = map[arr[j]];
// 写入结果集
for (let i = 0; i < indexArr.length; i++) {
result[indexArr[i]] = rightMidVal;
}
}
// 删除[rightMid, arr.length)索引中的其中一个值,剩下的中位数一定是leftMidVal
for (let j = rightMid; j < arr.length; j++) {
// 跟上面同理
const indexArr = map[arr[j]];
for (let i = 0; i < indexArr.length; i++) {
result[indexArr[i]] = leftMidVal;
}
}
return result;
}
// 输入
const n = Number.parseInt(readline());
const arr = readline()
.split(" ")
.map((s) => Number.parseInt(s));
const result = fn(n, arr);
// 输出
result.forEach((val) => print(val));
写的时候紧张了,这题也应该拿下的。
Dom
题:实现一个日期的组件 🔗
这个确实做不出来… 因为对日期的API
不是特别的熟悉。
html
代码如下:
<div id="js-container">
<div class="calendar">
<table>
<thead>
<tr>
<th class="pre">←</th>
<th colspan="5" class="date">2020.01</th>
<th class="next">→</th>
</tr>
<tr>
<th>一</th>
<th>二</th>
<th>三</th>
<th>四</th>
<th>五</th>
<th>六</th>
<th>日</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td>9</td>
<td>10</td>
<td>11</td>
<td>12</td>
<td>13</td>
</tr>
<tr>
<td>14</td>
<td>15</td>
<td>16</td>
<td>17</td>
<td>18</td>
<td>19</td>
<td>20</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>23</td>
<td>24</td>
<td>25</td>
<td>26</td>
<td>27</td>
</tr>
<tr>
<td>28</td>
<td>29</td>
<td>30</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
css
样式:
.current {
background-color: #4b8cff;
color: white;
}
#js-container {
display: flex;
justify-content: center;
margin-top: 30px;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
table td,
table th {
width: 100px;
height: 40px;
border-left: 1px solid #c1c1c1;
text-align: center;
}
table tr td:last-child,
table tr th:last-child {
border-right: 1px solid #c1c1c1;
}
table tr {
border-top: 1px solid #c1c1c1;
}
table tr:last-child {
border-bottom: 1px solid #c1c1c1;
}
js
如下:
function Calendar(year, month) {
this.month = month;
this.year = year;
this.el = null; // TODO 挂载元素
if (!this.el) {
return;
}
this.el.addEventListener("click", (event) => {
const target = event.target;
const isPre = target.classList.contains("pre");
const isNext = target.classList.contains("next");
if (!isPre && !isNext) {
return;
}
// TODO 更新month和year
this.el.innerHTML = this.innerHTML();
});
this.innerHTML = function () {
const year = +this.year || 0;
const month = (+this.month || 0) - 1;
const date = new Date();
// TODO 生成html字符串
return "";
};
}
这题就要我们填充三个TODO
。
前两个TODO
还好, 比较简单,难度在第三个TODO
。
function Calendar(year, month) {
this.month = month;
this.year = year;
this.el = document
.getElementById("js-container")
.getElementsByClassName("calendar")[0]
.getElementsByTagName("table")[0];
if (!this.el) {
return;
}
this.el.addEventListener("click", (event) => {
const target = event.target;
const isPre = target.classList.contains("pre");
const isNext = target.classList.contains("next");
if (!isPre && !isNext) {
return;
}
if (isPre) {
// 点击了上一个月
if (this.month === 1) {
this.year--;
this.month = 12;
} else {
this.month--;
}
} else if (isNext) {
// 点击了下一个月
if (this.month === 12) {
this.year++;
this.month = 1;
} else {
this.month++;
}
}
this.el.innerHTML = this.innerHTML();
});
this.innerHTML = function () {
const year = +this.year || 0;
const month = (+this.month || 0) - 1;
const cur = new Date(); // 当前时间
let xq = new Date(year, month, 1).getDay();
// 因为getDay中星期天返回的是0,我们需要把他设置为索引第6位,同时星期1到6设置成对应0-5的索引
// 我们只会获取第一天,因为完成整个日期数组并不会需要用到这个getDay()的API
// 我们只需要第一天正确的在数组里面的位置即可
xq = xq === 0 ? 6 : xq - 1;
// 获取这个月有多少天,这里设置为天数设置为0的意思是,获取上一个月的最后一天是这个月中的第几天
// 所以我们其实是获取了下一个月(month + 1)的上一个月(month)的最后一天处于那个月的第几天
// 而第几天也就意味着这个月有多少天(范围 1 - 31)
const day = new Date(year, month + 1, 0).getDate();
const r = [];
for (let i = 0; i < day; i++) {
const j = i + xq;
const row = Math.floor(j / 7);
const col = j % 7;
if (r[row] === undefined) {
r[row] = [];
}
// 如果正好是这个月的当天,就把对应的天数设置成负数
if (
cur.getDate() === i + 1 &&
cur.getMonth() === month &&
cur.getFullYear() === year
) {
r[row][col] = -(i + 1);
} else {
r[row][col] = i + 1;
}
}
let trs = "";
for (let i = 0; i < r.length; i++) {
let tds = "";
for (let j = 0; j < 7; j++) {
if (r[i][j] !== undefined) {
// 负数设置当天的样式
if (r[i][j] < 0) {
tds += `<td class="current">${-r[i][j]}</td>`;
} else {
tds += `<td>${r[i][j]}</td>`;
}
} else {
tds += `<td></td>`;
}
}
trs += `<tr>${tds}</tr>`;
}
return `<thead>
<tr>
<th class="pre"><</th>
<th colspan="5" class="date">
${this.year}
.
${this.month < 10 ? "0" + this.month : this.month}
</th>
<th class="next">></th></tr>
<tr>
<th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th><th>日</th>
</tr>
</thead>
<tbody>
${trs}
</tbody>`;
};
// new的时候第一次初始化
this.el.innerHTML = this.innerHTML();
}
new Calendar(2020, 9);
写半个多小时,写出来的,期间看了MDN
上的API
。
昨晚考完就断断续续的想了,今天再写就不会特别的慢。
感觉非常棒的一道题。
放个运行的图:
消消乐(栈题) 🔗
写这题剩 10 分钟,还没写完系统就交卷了…
给定n
个字符串,如果有两个相同的字符挨在一起,就把它们消去,消去之后的字符串如果符合规则也要继续消去,输出需要消去的次数
输入:
2
abcddcba
101
输出:
4 // 消去了dd,cc相碰消去,bb相碰消去,aa相碰消去,共消去4此
0 // 无法消去
这题我刚看到就觉得是考察栈的知识点的。
function fn(n, arr) {
const result = [];
for (let i = 0; i < n; i++) {
if (arr[i].length === 0 || arr[i].length === 1) {
result.push(0);
continue;
}
const strArr = arr[i].split("");
const stack = [];
stack[0] = strArr[0];
let j = 1;
let count = 0;
while (j < strArr.length) {
const peek = stack[stack.length - 1];
if (peek === strArr[j]) {
// 消去
count++;
stack.length--;
} else {
// push进数组
stack[stack.length] = strArr[j];
}
j++;
}
result.push(count);
}
return result;
}
const n = Number.parseInt(readline());
const arr = [];
for (let i = 0; i < n; i++) {
arr.push(readline());
}
const result = fn(n, arr);
result.forEach((val) => print(val));