剑指offer题目汇总(二)

来源:互联网 发布:反应热效应的测定数据 编辑:程序博客网 时间:2024/04/30 02:14

剑指offer 面试题 11-20

作者代码下载地址 https://github.com/zhedahht/CodingInterviewChinese2

面试题11:旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。

int MinInOrder(int* numbers, int index1, int index2);int Min(int* numbers, int length){    if(numbers == nullptr || length <= 0)        throw new std::exception("Invalid parameters");    int index1 = 0;    int index2 = length - 1;    int indexMid = index1;    while(numbers[index1] >= numbers[index2])    {        // 如果index1和index2指向相邻的两个数,        // 则index1指向第一个递增子数组的最后一个数字,        // index2指向第二个子数组的第一个数字,也就是数组中的最小数字        if(index2 - index1 == 1)        {            indexMid = index2;            break;        }        // 如果下标为index1、index2和indexMid指向的三个数字相等,        // 则只能顺序查找        indexMid = (index1 + index2) / 2;        if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])            return MinInOrder(numbers, index1, index2);        // 缩小查找范围        if(numbers[indexMid] >= numbers[index1])            index1 = indexMid;        else if(numbers[indexMid] <= numbers[index2])            index2 = indexMid;    }    return numbers[indexMid];}int MinInOrder(int* numbers, int index1, int index2){    int result = numbers[index1];    for(int i = index1 + 1; i <= index2; ++i)    {        if(result > numbers[i])            result = numbers[i];    }    return result;}

面试题12:矩阵中的路径

题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用下划线标出)。但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
// A B T G
// C F C S
// J D E H

bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int& pathLength, bool* visited);bool hasPath(const char* matrix, int rows, int cols, const char* str){    if(matrix == nullptr || rows < 1 || cols < 1 || str == nullptr)        return false;    bool *visited = new bool[rows * cols];    memset(visited, 0, rows * cols);    int pathLength = 0;    for(int row = 0; row < rows; ++row)    {        for(int col = 0; col < cols; ++col)        {            if(hasPathCore(matrix, rows, cols, row, col, str,                pathLength, visited))            {                return true;            }        }    }    delete[] visited;    return false;}bool hasPathCore(const char* matrix, int rows, int cols, int row,    int col, const char* str, int& pathLength, bool* visited){    if(str[pathLength] == '\0')        return true;    bool hasPath = false;    if(row >= 0 && row < rows && col >= 0 && col < cols        && matrix[row * cols + col] == str[pathLength]        && !visited[row * cols + col])    {        ++pathLength;        visited[row * cols + col] = true;        hasPath = hasPathCore(matrix, rows, cols, row, col - 1,            str, pathLength, visited)            || hasPathCore(matrix, rows, cols, row - 1, col,                str, pathLength, visited)            || hasPathCore(matrix, rows, cols, row, col + 1,                str, pathLength, visited)            || hasPathCore(matrix, rows, cols, row + 1, col,                str, pathLength, visited);        if(!hasPath)        {            --pathLength;            visited[row * cols + col] = false;        }    }    return hasPath;}

面试题13:机器人的运动范围

题目:地上有一个m行n列的方格。一个机器人从坐标(0, 0)的格子开始移动,它每一次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格(35, 37),因为3+5+3+7=18。但它不能进入方格(35, 38),因为3+5+3+8=19。请问该机器人能够到达多少个格子?

int movingCountCore(int threshold, int rows, int cols, int row, int col, bool* visited);bool check(int threshold, int rows, int cols, int row, int col, bool* visited);int getDigitSum(int number);int movingCount(int threshold, int rows, int cols){    if(threshold < 0 || rows <= 0 || cols <= 0)        return 0;    bool *visited = new bool[rows * cols];    for(int i = 0; i < rows * cols; ++i)        visited[i] = false;    int count = movingCountCore(threshold, rows, cols,        0, 0, visited);    delete[] visited;    return count;}int movingCountCore(int threshold, int rows, int cols, int row,    int col, bool* visited){    int count = 0;    if(check(threshold, rows, cols, row, col, visited))    {        visited[row * cols + col] = true;        count = 1 + movingCountCore(threshold, rows, cols,            row - 1, col, visited)            + movingCountCore(threshold, rows, cols,                row, col - 1, visited)            + movingCountCore(threshold, rows, cols,                row + 1, col, visited)            + movingCountCore(threshold, rows, cols,                row, col + 1, visited);    }    return count;}bool check(int threshold, int rows, int cols, int row, int col,    bool* visited){    if(row >= 0 && row < rows && col >= 0 && col < cols        && getDigitSum(row) + getDigitSum(col) <= threshold        && !visited[row* cols + col])        return true;    return false;}int getDigitSum(int number){    int sum = 0;    while(number > 0)    {        sum += number % 10;        number /= 10;    }    return sum;}

面试题14:剪绳子

题目:你一根长度为n绳子,把绳子剪成m段(m、n都是整数,n>1并且m≥1)。每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1]…*k[m]可能的最大乘积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18。

// ====================动态规划====================int maxProductAfterCutting_solution1(int length){    if(length < 2)        return 0;    if(length == 2)        return 1;    if(length == 3)        return 2;    int* products = new int[length + 1];    products[0] = 0;    products[1] = 1;    products[2] = 2;    products[3] = 3;    int max = 0;    for(int i = 4; i <= length; ++i)    {        max = 0;        for(int j = 1; j <= i / 2; ++j)        {            int product = products[j] * products[i - j];            if(max < product)                max = product;            products[i] = max;        }    }    max = products[length];    delete[] products;    return max;}// ====================贪婪算法====================int maxProductAfterCutting_solution2(int length){    if(length < 2)        return 0;    if(length == 2)        return 1;    if(length == 3)        return 2;    // 尽可能多地减去长度为3的绳子段    int timesOf3 = length / 3;    // 当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段。    // 此时更好的方法是把绳子剪成长度为2的两段,因为2*2 > 3*1。    if(length - timesOf3 * 3 == 1)        timesOf3 -= 1;    int timesOf2 = (length - timesOf3 * 3) / 2;    return (int) (pow(3, timesOf3)) * (int) (pow(2, timesOf2));}

面试题15:二进制中1的个数

题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。

int NumberOf1_Solution1(int n){    int count = 0;    unsigned int flag = 1;    while (flag)    {        if (n & flag)            count++;        flag = flag << 1;    }    return count;}int NumberOf1_Solution2(int n){    int count = 0;    while (n)    {        ++count;        n = (n - 1) & n;    }    return count;}

面试题16:数值的整数次方

题目:实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。

bool g_InvalidInput = false;bool equal(double num1, double num2);double PowerWithUnsignedExponent(double base, unsigned int exponent);double Power(double base, int exponent){    g_InvalidInput = false;    if (equal(base, 0.0) && exponent < 0)    {        g_InvalidInput = true;        return 0.0;    }    unsigned int absExponent = (unsigned int) (exponent);    if (exponent < 0)        absExponent = (unsigned int) (-exponent);    double result = PowerWithUnsignedExponent(base, absExponent);    if (exponent < 0)        result = 1.0 / result;    return result;}/*double PowerWithUnsignedExponent(double base, unsigned int exponent){    double result = 1.0;    for (int i = 1; i <= exponent; ++i)        result *= base;    return result;}*/double PowerWithUnsignedExponent(double base, unsigned int exponent){    if (exponent == 0)        return 1;    if (exponent == 1)        return base;    double result = PowerWithUnsignedExponent(base, exponent >> 1);    result *= result;    if ((exponent & 0x1) == 1)        result *= base;    return result;}bool equal(double num1, double num2){    if ((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))        return true;    else        return false;}

面试题17:打印1到最大的n位数

题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。

bool Increment(char* number);void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index);// ====================方法一====================void Print1ToMaxOfNDigits_1(int n){    if (n <= 0)        return;    char *number = new char[n + 1];    memset(number, '0', n);    number[n] = '\0';    while (!Increment(number))    {        PrintNumber(number);    }    delete[]number;}// 字符串number表示一个数字,在 number上增加1// 如果做加法溢出,则返回true;否则为falsebool Increment(char* number){    bool isOverflow = false;    int nTakeOver = 0;    int nLength = strlen(number);    for (int i = nLength - 1; i >= 0; i--)    {        int nSum = number[i] - '0' + nTakeOver;        if (i == nLength - 1)            nSum++;        if (nSum >= 10)        {            if (i == 0)                isOverflow = true;            else            {                nSum -= 10;                nTakeOver = 1;                number[i] = '0' + nSum;            }        }        else        {            number[i] = '0' + nSum;            break;        }    }    return isOverflow;}// ====================方法二====================void Print1ToMaxOfNDigits_2(int n){    if (n <= 0)        return;    char* number = new char[n + 1];    number[n] = '\0';    for (int i = 0; i < 10; ++i)    {        number[0] = i + '0';        Print1ToMaxOfNDigitsRecursively(number, n, 0);    }    delete[] number;}void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index){    if (index == length - 1)    {        PrintNumber(number);        return;    }    for (int i = 0; i < 10; ++i)    {        number[index + 1] = i + '0';        Print1ToMaxOfNDigitsRecursively(number, length, index + 1);    }}

面试题18(一):在O(1)时间删除链表结点

题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted){    if(!pListHead || !pToBeDeleted)        return;    // 要删除的结点不是尾结点    if(pToBeDeleted->m_pNext != nullptr)    {        ListNode* pNext = pToBeDeleted->m_pNext;        pToBeDeleted->m_nValue = pNext->m_nValue;        pToBeDeleted->m_pNext = pNext->m_pNext;        delete pNext;        pNext = nullptr;    }    // 链表只有一个结点,删除头结点(也是尾结点)    else if(*pListHead == pToBeDeleted)    {        delete pToBeDeleted;        pToBeDeleted = nullptr;        *pListHead = nullptr;    }    // 链表中有多个结点,删除尾结点    else    {        ListNode* pNode = *pListHead;        while(pNode->m_pNext != pToBeDeleted)        {            pNode = pNode->m_pNext;        }        pNode->m_pNext = nullptr;        delete pToBeDeleted;        pToBeDeleted = nullptr;    }}

面试题18(二):删除链表中重复的结点

题目:在一个排序的链表中,如何删除重复的结点?例如,在图3.4(a)中重复结点被删除之后,链表如图3.4(b)所示。

void DeleteDuplication(ListNode** pHead){    if(pHead == nullptr || *pHead == nullptr)        return;    ListNode* pPreNode = nullptr;    ListNode* pNode = *pHead;    while(pNode != nullptr)    {        ListNode *pNext = pNode->m_pNext;        bool needDelete = false;        if(pNext != nullptr && pNext->m_nValue == pNode->m_nValue)            needDelete = true;        if(!needDelete)        {            pPreNode = pNode;            pNode = pNode->m_pNext;        }        else        {            int value = pNode->m_nValue;            ListNode* pToBeDel = pNode;            while(pToBeDel != nullptr && pToBeDel->m_nValue == value)            {                pNext = pToBeDel->m_pNext;                delete pToBeDel;                pToBeDel = nullptr;                pToBeDel = pNext;            }            if(pPreNode == nullptr)                *pHead = pNext;            else                pPreNode->m_pNext = pNext;            pNode = pNext;        }    }}

面试题19:正则表达式匹配

题目:请实现一个函数用来匹配包含’.’和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’‘表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab*ac*a”匹配,但与”aa.a”及”ab*a”均不匹配。

bool matchCore(const char* str, const char* pattern);bool match(const char* str, const char* pattern){    if(str == nullptr || pattern == nullptr)        return false;    return matchCore(str, pattern);}bool matchCore(const char* str, const char* pattern){    if(*str == '\0' && *pattern == '\0')        return true;    if(*str != '\0' && *pattern == '\0')        return false;    if(*(pattern + 1) == '*')    {        if(*pattern == *str || (*pattern == '.' && *str != '\0'))            // 进入有限状态机的下一个状态            return matchCore(str + 1, pattern + 2)            // 继续留在有限状态机的当前状态             || matchCore(str + 1, pattern)            // 略过一个'*'             || matchCore(str, pattern + 2);        else            // 略过一个'*'            return matchCore(str, pattern + 2);    }    if(*str == *pattern || (*pattern == '.' && *str != '\0'))        return matchCore(str + 1, pattern + 1);    return false;}

面试题20:表示数值的字符串

题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串“+100”、“5e2”、“-123”、“3.1416”及“-1E-16”都表示数值,但“12e”、“1a3.14”、“1.2.3”、“+-5”及“12e+5.4”都不是

bool scanUnsignedInteger(const char** str);bool scanInteger(const char** str);// 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是// 整数(可以有正负号,也可以没有),而B是一个无符号整数bool isNumeric(const char* str){    if(str == nullptr)        return false;    bool numeric = scanInteger(&str);    // 如果出现'.',接下来是数字的小数部分    if(*str == '.')    {        ++str;        // 下面一行代码用||的原因:        // 1. 小数可以没有整数部分,例如.123等于0.123;        // 2. 小数点后面可以没有数字,例如233.等于233.0;        // 3. 当然小数点前面和后面可以有数字,例如233.666        numeric = scanUnsignedInteger(&str) || numeric;    }    // 如果出现'e'或者'E',接下来跟着的是数字的指数部分    if(*str == 'e' || *str == 'E')    {        ++str;        // 下面一行代码用&&的原因:        // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;        // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4        numeric = numeric && scanInteger(&str);    }    return numeric && *str == '\0';}bool scanUnsignedInteger(const char** str){    const char* before = *str;    while(**str != '\0' && **str >= '0' && **str <= '9')        ++(*str);    // 当str中存在若干0-9的数字时,返回true    return *str > before;}// 整数的格式可以用[+|-]B表示, 其中B为无符号整数bool scanInteger(const char** str){    if(**str == '+' || **str == '-')        ++(*str);    return scanUnsignedInteger(str);}
0 0
原创粉丝点击