《剑指offer》读书笔记·第一章、面试的流程

333 阅读2分钟

面试一般有3种形式:

  1. 电话面试
    此过程中要特别注意“清晰”。既要理解清晰,知道面试官想要问的什么问题,也要表达清晰,让面试官理解你的解题思路。千万不能不懂装懂,答非所问
  2. 上机操作
    思定而后动。在编码之前,先对整个问题有个大概规划,边界条件、异常情况有个好的处理思路。然后,还要有个好的编码规范。
  3. 现场面试
    用star模型(项目背景、自己完成的任务、为了完成任务做了哪些工作和怎么做的、自己的贡献)描述好自己所做的项目。
    技术面试者应该具备以下素质:
    1. 基础知识扎实,包括变成语言、数据结构、算法等
    2. 能写出正确的,完整的,高质量的代码
    3. 能思路清晰的分析复杂问题
    4. 能从时间和空间复杂度优化算法
    5. 优秀的沟通能力,学习能力,发散思维

文中列举了两个改错的例子:
第一个是把一个字符串转化成整数,代码是这样的:

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(&reg,pattern,REG_EXTENDED);
    if (compCode != 0) {
        if(error != NULL)
            *error = StrToIntErrorRegError;
        return 0;
    }
    int regError = regexec(&reg,string,nmatch,pm,0);
    if(regError == REG_NOMATCH)
    {
        regfree(&reg);
        if(error != NULL)
            *error = StrToIntErrorNotNumber;
        return 0;
    }
    regfree(&reg);
    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;
}