Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
1. 背景
本人虽然毕业于软件学院,可是对于算法还是入门级别。2020年第一次开始刷 leetcode 上的算法题,当时懵懵懂懂,几乎靠背。由于开发经验少能力也弱,面试的时候都没有遇到过算法题。到了2021年刷了两次,也是比较随意,发现以前刷过的题目又需要重新刷了。这一年投过简历面了几家公司,发现基本知识还是不过关,更没有机会去参加有算法题的面试了。时间来到2022年,也就是今年,有幸面到一家公司考了快排,当时有刻意准备就写出来了,然后面试的时候还问了移动零,当时意识到自己刷过这个题目,可就是想不起来怎么做,口述暴力解法的解法的时候也是囫囵吞枣,没有说到重点。那次面试结束后果断去刷 leetcode 了,这一次发现比以前熟练了一些,然后刷的时候不再刻意强调数量,而是更看重“质量”,每道题最少做两遍,直到看到题就能写出答案。做完之后还在掘金上写解析,分析解题思路。终于,昨天有幸参与一场机试,三道题做了两道,测试通过率分别是70%,85%。
2. 题目
2.1 能力匹配问题
题目没有记录下来,这里说下题目的大概内容。有 n 个人,每个人的能力值为 p,当这个人或者和另一人组合达到最低能力标准 target ,就说明这个人或者这两个人是符合能力标准的。问最多有多少个符合能力标准。例如
输入:
6
3 3 0 5 5 9
8
输出:
3
下面是我的答案,测试用例通过率只有70%,没有找到问题所在,这里就简单说明一下解题思路。首先对数组进行排序,接着依次遍历,符合标准就记录增加1,不符合标准就去 savedNums 找,看能否找一个凑合起来达到标准,还是达不到就先存到数组 savedNums 中。当时是在牛客网上做的,运行的时间超过2s,也就是说时间复杂度太大,可能需要使用二分查找去优化,不过没有再花时间尝试。
let n = parseInt(readline()); // 输入个数,这项输入没有用到
let str = readline(); // 多个能力值
let target = parseInt(readline()); // 需要达到的最低能力标准
let arr = str.split(" ");
arr.sort((a, b) => a - b);
let res = 0,
savedNums = [];
for (const v of arr) { // 遍历所有的能力值
const num = parseInt(v);
if (num >= target) { // 如果能力值达到标准则记录+1
res++;
} else { // 如果能力值不够就遍历 savedNums ,测试是否刻意拼凑起来达到标准,如果还是达不到标准就放到 savedNums 里面。
let hasTargetNum = false;
for (let i = 0; i < savedNums.length; i++) {
if (savedNums[i] + num >= target) {
res++;
savedNums.splice(i, 1);
hasTargetNum = true;
break;
}
}
if (!hasTargetNum) {
savedNums.push(num);
}
}
}
print(res);
2.2 括号匹配问题
大概题意是,输入一组括号,其中每个括号都是(,),{,},[,]中的一种,输入左括号之后按照正确的顺序有右括号进行匹配说明是有效括号,求出有效括号的最大深度。例如
输入:
({}{()})
输出:
3
这道理类似于 leetdode 的 有效的括号,于是我按照之前的解题思路来做,最后测试用例的通过率是85%。首先遍历输入的字符串,如果是左括号放入一个栈当中,并记录栈的最大长度;如果不是左括号,先判断是不是和栈弹出的括号匹配,匹配并且 deep 小于栈的最大长度就让 deep 递增,不匹配就终止遍历,说明输入的是一组无效的括号。
let str = readline();
let obj = {
"(": ")",
"{": "}",
"[": "]",
};
let stack = [];
let maxStack = 0;
let deep = 0;
for (const char of str) {
if (obj[char]) { // 如果是左括号则保存到 stack 中
stack.push(char);
maxStack = Math.max(maxStack, stack.length); // 记录 stack 的最大长度
} else {
if (char === obj[stack.pop()]) {
if (deep < maxStack) { // 如果和 stack 弹出的括号匹配且 deep 小于 maxStack 则 deep 递增。
deep++;
}
} else {
break;
}
}
}
print(deep);
2.3 九宫格输入模拟
题意是,模拟手机九宫格输入,默认是数字模式,可以输入数字0,1,2,3,4,5,6,7,8,9,通过 # 可以切换模式,也就是按下 # 会变成字母模式,再按下 # 会变回数字模式,如果是字母模式,输入和输出对应为(其中括号中是输出):0(空格),1(,.),2(abc),3(def),4(ghi),5(jkl),6(mno),7(qprs),8(tuv),9(wxyz)。另外,还有一个符号“/”,如果是数字模式代表空格,如果是字母模式代表截断。例如
输入:
#2222/2#348#8822
输出:
aa348ub
由于考试时间不够了,所以本题的答案并没有提交,也就不知道测试通过率,但如果测试的话,通过率应该是有的。
根据题意,可以将输入分成三部分来处理。第一部分,输入的是#号,可以用来切换模式,通过布尔值 isNumMode 保存,对于输入字母状态下这个符号还有截断功能,所以就需要调用 accumulateChar 函数;第二部分,输入的是/号,如果是数字模式则变成空格,如果是字母模式则调用 accumulateChar 函数进行截断;第三部分,输入的是数字,如果是数字模式直接累加,如果是字母模式,combineChar 对象有记录则使序号递增,combineChar 对象没有记录则记录到该对象中并且调用 accumulateChar 函数进行截断。最后,输入完成还会调用 accumulateChar 函数进行截断。这个 accumulateChar 函数用来拿到 combineChar 对象保存的字符并且清空 combineChar 对象,从而实现字母输入的截断。
let str = readline();
let isNumMode = true;
let numsStr = "0123456789";
let res = "";
let charList = [" ", ",.", "abc", "def", "ghi", "jkl", "mno", "qprs", "tuv", "wxyz"];
const defaultCombineChar = {
num: -1,
char: "",
currentIndex: -1,
};
let combineChar = { ...defaultCombineChar };
function accumulateChar() {
// 如果 combineChar 中有保存字母,则累加进来,并清空 combineChar
if (combineChar.char) {
const index = combineChar.currentIndex % combineChar.char.length;
const char = combineChar.char;
res += char[index];
combineChar = { ...defaultCombineChar };
}
}
for (const char of str) {
if (char === "#") {
// 1. 处理 # 号,用来切换不同的输入模式
isNumMode = !isNumMode;
accumulateChar();
} else if (numsStr.includes(char)) {
if (isNumMode) {
res += char; // 2. 如果是数字直接累加
} else {
const currentNum = Number(char); // 3. 如果是字母的时候,将键盘输入的数字,对应的所有字符和当前选中的字符序号都保存下来
if (combineChar.num === currentNum) {
combineChar.currentIndex++;
} else {
accumulateChar();
Object.assign(combineChar, {
num: currentNum,
char: charList[currentNum],
currentIndex: 0,
});
}
}
} else if (char === "/") { // 4. 处理 /,如果是数字模式则转化成空格,如果是字母模式则输出之前累加的字母
if (isNumMode) {
res += " ";
} else {
accumulateChar();
}
}
}
if (!isNumMode) {
accumulateChar();
}
console.log(res);
总结
通过这次机考,有两个问题是值的反思的。第一,需要注意时间,解题的时候需要全身心的投入,以最快的速度去写好思路然后进行多次验证。这次机试虽然有两个半小时的时间,可是自己还是只完成了两道题;第二,需要不断的实践和思考,刷 leetcode 的时候不要只想着依赖答案,要多靠自己的能力去思考,自己会怎么解答,为什么别人会有这么好的解题思路。有的人刷50多道就可以解决很多问题,为什么自己100多道遇到相似的问题甚至是原题还是解答不出来。