剑指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);}
- 剑指offer题目汇总(二)
- 剑指offer题目汇总(一)
- 剑指offer题目汇总(三)
- 剑指offer题目思想汇总
- 剑指offer 面试题题目汇总
- [面试算法] 剑指Offer题目代码汇总
- 剑指offer--DP类题目汇总
- 剑指offer编程题目汇总(更新中。。)
- 剑指offer算法编程题目部分汇总(解法略)
- 牛客网做题总结:剑指offer中题目,java版二
- 剑指Offer题目JAVA版思路与代码(二)
- 计算机网络---基础题目汇总二
- 操作系统---基础题目汇总二
- 机器学习题目汇总二
- 剑指offer题目集
- 剑指offer题目记录
- 剑指offer题目概括
- 剑指offer题目
- 455. Assign Cookies | 分配饼干
- android常用的一些UI调试命令am,pm
- 一个有趣的遭遇:dubbo超时追踪出来的httpclient超时问题
- Android 实现视频播放的两种方式
- 6人执行任务
- 剑指offer题目汇总(二)
- Bluemix结合RabbitMq实现消息发送与接收实例
- MongoDB 数组查询
- 程序员想玩转大数据:需要知晓的12种工具
- win7+vs2012下使用gtest
- Javascript中回调函数的使用
- CAS单点登录3--服务端登录页个性化
- angular学习整理(二)---指令
- GCC