面试一般有3种形式:
- 电话面试
此过程中要特别注意“清晰”。既要理解清晰,知道面试官想要问的什么问题,也要表达清晰,让面试官理解你的解题思路。千万不能不懂装懂,答非所问 - 上机操作
思定而后动。在编码之前,先对整个问题有个大概规划,边界条件、异常情况有个好的处理思路。然后,还要有个好的编码规范。 - 现场面试
用star模型(项目背景、自己完成的任务、为了完成任务做了哪些工作和怎么做的、自己的贡献)描述好自己所做的项目。
技术面试者应该具备以下素质:- 基础知识扎实,包括变成语言、数据结构、算法等
- 能写出正确的,完整的,高质量的代码
- 能思路清晰的分析复杂问题
- 能从时间和空间复杂度优化算法
- 优秀的沟通能力,学习能力,发散思维
文中列举了两个改错的例子:
第一个是把一个字符串转化成整数,代码是这样的:
int StrToInt(char *string)
{
int number = 0;
while(*string!=0)
{
number = number * 10 + *string - '0';
++string;
}
return number;
}
那么我们来看看这个题应该怎么改呢?读一读这段代码,发现他已经有了正确性,但是完整性不够,没有对边界条件和异常情况作出处理。既然这样,我们就为他添上吧。
enum StrToIntError {
StrToIntErrorNULL = 0,
StrToIntErrorEmpty = 1,
StrToIntErrorRegError = 2,
StrToIntErrorNotNumber = 3,
StrToIntErrorOverflow = 4
};
int strToInt(char *string , enum StrToIntError *error)
{
//判断是否为空
if(string == NULL)
{
if(error != NULL)
*error = StrToIntErrorNULL;
return 0;
}
//判断是否为空字符串
if(strlen(string) == 0){
if(error != NULL)
*error = StrToIntErrorEmpty;
return 0;
}
//判断是否为数字
regex_t reg;
const char *pattern = "^[+-]?[0-9]*$";
const size_t nmatch = 1;
regmatch_t pm[1];
int compCode = regcomp(®,pattern,REG_EXTENDED);
if (compCode != 0) {
if(error != NULL)
*error = StrToIntErrorRegError;
return 0;
}
int regError = regexec(®,string,nmatch,pm,0);
if(regError == REG_NOMATCH)
{
regfree(®);
if(error != NULL)
*error = StrToIntErrorNotNumber;
return 0;
}
regfree(®);
int number = 0;
bool isNegative = false;
while(*string != '\0')
{
//判断是否溢出
int nextDigit = *string - '0';
if(number > INT_MAX/10){
if(error != NULL)
*error = StrToIntErrorOverflow;
return 0;
}else if (number == INT_MAX/10){
if (isNegative && nextDigit > 8) {
if(error != NULL)
*error = StrToIntErrorOverflow;
return 0;
}else if (!isNegative && nextDigit > 7){
if(error != NULL)
*error = StrToIntErrorOverflow;
return 0;
}
}
//计算的时候避开头部的+和-
if(*string == '-'){
isNegative = true;
}else if (*string != '+') {
number = number * 10 + *string - '0';
}
++string;
}
number = isNegative ? -number : number;
return number;
}
第二个是找到链表中倒数第k个节点
ListNode *FindKthToTail(ListNode * pListHead, unsigned int k)
{
if(pListHead == nullptr)
return nullptr;
ListNode *pAhead = pListHead;
ListNode *pBhead = nullptr;
for(unsigned int i = 0; i < k; ++i)
{
pAhead = pAhead->m_pNext;
}
pBhead = pListHead;
while(pAhead->m_pNext != nullptr)
{
pAhead = pAhead->m_pNext;
pBhead = pBhead->m_pNext;
}
return pBhead;
}
我们来看看这段代码怎么来完善他。
ListNode *FindKthToTail(ListNode * pListHead, unsigned int k)
{
//判断传入的链表是否为空
if(pListHead == nullptr)
return nullptr;
ListNode *pAhead = pListHead;
ListNode *pBhead = nullptr;
for(unsigned int i = 0; i < k; ++i)
{
pAhead = pAhead->m_pNext;
//判断next是否为空
if(pAhead == nullptr)
return nullptr;
}
pBhead = pListHead;
while(pAhead->m_pNext != nullptr)
{
pAhead = pAhead->m_pNext;
pBhead = pBhead->m_pNext;
}
return pBhead;
}