腾讯IG部门 前端日常实习一面3.6
应该是IG部门???。。有点没听清
投了好久好久了,去年就已经投了,一直没结果。结果前几天起床收到邮件参加面试,其实心里第一反应是刷kpi?因为看到好多面经都是一下就挂了。。
面试官叫我把摄像头开开,自己又不开,玛德能不能来点尊重人的面试官。。听声音估计二十多岁,全程都是敷衍漫不经心
上来自我介绍然后问了些无关紧要的题,就让我做三道算法题(其实已经感觉是kpi了,因为面了那么多家第一次见不问前端知识直接做算法题的。。。我在写的途中甚至怀疑我是不是面试错了,面的不是前端岗。。)
算法题不难,第一道算法题是将两个有序数组合并为一个有序数组,leetcode上应该有,用了时间复杂度和空间复杂度都是O(n+m)的方式完成,然后人家问我思路,其实就是双指针+循环,结果人家问我有没有什么改进办法,damn我想不到,时间复杂度想五分钟想不到更低的,人家问我空间复杂度有没有更低的,我想了一会弄了十分钟结果是错的哈哈,人家又说给我五分钟再想一下,随便弄了下跟人家讲了下思路,跳过。
- 以下是将两个有序数组合并为一个有序数组的 JavaScript 实现:
function mergeSortedArrays(arr1, arr2) {
let mergedArray = [];
let i = 0, j = 0;
// 比较两个数组的元素,将较小的元素放入新数组
while (i < arr1.length && j < arr2.length) {
if (arr1[i] < arr2[j]) {
mergedArray.push(arr1[i]);
i++;
} else {
mergedArray.push(arr2[j]);
j++;
}
}
// 将剩余的元素添加到新数组
while (i < arr1.length) {
mergedArray.push(arr1[i]);
i++;
}
while (j < arr2.length) {
mergedArray.push(arr2[j]);
j++;
}
return mergedArray;
}
// 示例
const arr1 = [1, 3, 5, 7];
const arr2 = [2, 4, 6, 8];
console.log(mergeSortedArrays(arr1, arr2)); // 输出 [1, 2, 3, 4, 5, 6, 7, 8]
当然可以改进。下面是一种稍微改进的方法,它使用了 Array.concat() 和 Array.splice() 方法来更有效地合并两个有序数组:
function mergeSortedArrays(arr1, arr2) {
let mergedArray = [...arr1]; // 复制第一个数组
for (let i = 0; i < arr2.length; i++) {
let inserted = false;
for (let j = 0; j < mergedArray.length; j++) {
if (arr2[i] <= mergedArray[j]) {
mergedArray.splice(j, 0, arr2[i]); // 在合适的位置插入元素
inserted = true;
break;
}
}
if (!inserted) {
mergedArray = mergedArray.concat(arr2.slice(i)); // 将剩余的元素添加到末尾
break;
}
}
return mergedArray;
}
// 示例
const arr1 = [1, 3, 5, 7];
const arr2 = [2, 4, 6, 8];
console.log(mergeSortedArrays(arr1, arr2)); // 输出 [1, 2, 3, 4, 5, 6, 7, 8]
这种方法将第一个数组 arr1 复制到 mergedArray 中,然后迭代第二个数组 arr2 中的每个元素。对于每个元素,它在 mergedArray 中找到合适的位置,并使用 splice() 方法插入。如果插入过程中已经到达 mergedArray 的末尾,那么剩余的 arr2 元素将直接通过 concat() 方法连接到 mergedArray 的末尾。
这个函数接受两个有序数组作为参数,并返回一个合并后的有序数组。在函数中,我们使用两个指针分别指向两个数组的开头,然后比较两个指针所指元素的大小,将较小的元素添加到新数组中,并将相应的指针向前移动。最后,将剩余的元素添加到新数组中,即可得到合并后的有序数组。
我非常怀疑,人家在我写的时候,闭着麦玩手机,我写完之后叫他都没反应还要多叫几次,而且就问我,你有什么改进办法有什么思路,好的你写吧,然后继续闭麦,严重怀疑是kpi,不给个引导随便弄弄,行你厉害
第二题也不难,是leetcode中的最大子数组,用for循环和常熟就能在时间复杂度O(n)和空间复杂度O(1)的情况下完成,人家又问下我思路就跳过
最大子数组问题是一个经典的动态规划问题,也可以通过分治法求解。以下是一个使用动态规划的 JavaScript 实现:
function maxSubarray(arr) {
let maxEndingHere = arr[0];
let maxSoFar = arr[0];
for (let i = 1; i < arr.length; i++) {
maxEndingHere = Math.max(arr[i], maxEndingHere + arr[i]);
maxSoFar = Math.max(maxSoFar, maxEndingHere);
}
return maxSoFar;
}
// 示例
const arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4];
console.log(maxSubarray(arr)); // 输出 6 (对应子数组 [4, -1, 2, 1])
这个函数接受一个整数数组 arr,并返回数组中的最大子数组之和。在函数中,我们使用了两个变量 maxEndingHere 和 maxSoFar 来追踪当前子数组的最大和以及全局最大和。我们遍历数组中的每个元素,对于每个元素,我们更新 maxEndingHere 为当前元素的值或者当前元素加上 maxEndingHere,然后更新 maxSoFar 为 maxSoFar 和 maxEndingHere 中的较大值。最后,返回 maxSoFar 即可得到最大子数组的和。
这个算法的时间复杂度为 O(n),其中 n 是数组的长度。
第三题是让我创建二叉排序树。。。写一个构造函数。。。我不会。。。数据结构用c学的而且已经学了一年半了忘光了。。
下面是一个 JavaScript 构造函数,用于创建二叉搜索树(Binary Search Tree):
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
} else {
this.insertNode(this.root, newNode);
}
}
insertNode(node, newNode) {
if (newNode.value < node.value) {
if (node.left === null) {
node.left = newNode;
} else {
this.insertNode(node.left, newNode);
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
this.insertNode(node.right, newNode);
}
}
}
}
// 示例
const bst = new BinarySearchTree();
bst.insert(10);
bst.insert(5);
bst.insert(15);
bst.insert(3);
bst.insert(8);
console.log(bst.root); // 输出整棵二叉搜索树的根节点
这个代码定义了两个类,TreeNode 类表示二叉搜索树的节点,它有一个 value 属性表示节点的值,以及 left 和 right 属性表示左右子节点。BinarySearchTree 类表示二叉搜索树,它有一个 root 属性表示根节点。insert 方法用于插入新节点到二叉搜索树中,insertNode 方法是一个辅助方法,用于递归地插入节点。
- 后面看我简历问了我防抖节流,问我怎么实现,我就说用定时器settimeout实现,问我还有别的实现方法吗我说我不知道。。
防抖(Debounce)和节流(Throttle)都是用来控制函数调用频率的技术,它们可以限制函数的执行次数,特别是在处理频繁触发的事件时非常有用。下面是它们的基本实现:
防抖(Debounce):
防抖的原理是,当事件被触发后,一定时间内不再触发事件,则执行该事件。如果在这个时间内事件被再次触发,则重新开始计时。
function debounce(func, delay) {
let timerId;
return function() {
const context = this;
const args = arguments;
clearTimeout(timerId);
timerId = setTimeout(function() {
func.apply(context, args);
}, delay);
};
}
节流(Throttle):
节流的原理是,当事件被触发后,在一定时间内只执行一次,不管事件触发频率有多高。
function throttle(func, delay) {
let shouldRun = true;
return function() {
if (!shouldRun) return;
const context = this;
const args = arguments;
shouldRun = false;
func.apply(context, args);
setTimeout(function() {
shouldRun = true;
}, delay);
};
}
使用时,将需要控制频率的函数作为参数传递给 debounce 或 throttle,并指定所需的延迟时间。例如:
function handleScroll() {
console.log('Scrolled');
}
const debounceScroll = debounce(handleScroll, 300);
window.addEventListener('scroll', debounceScroll);
const throttleScroll = throttle(handleScroll, 300);
window.addEventListener('scroll', throttleScroll);
在这个示例中,handleScroll 函数在滚动事件触发时会被控制。debounceScroll 是防抖后的处理函数,而 throttleScroll 是节流后的处理函数。
-
然后又问了其它无关紧要的问题,问我能实习多久什么什么之类的
-
最后是反问,我问他有什么需要改进的他说我还可以,然后我问了个我非常疑惑的就是,我面试的前端,为什么不问我三件套计网浏览器那些知识而是上来就是三道算法题,他说这是因为业务中真正会用到的,他说那些计网vue浏览器等等知识都是死记硬背。。。好吧fine我无话可说,仁者见仁智者见智吧