剑指offer 试题11~20
2017-12-06 12:31
423 查看
试题11:旋转数组的最小数字
这题当时没想到思路,看的《剑指offer》class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { if(rotateArray.size() == 0) return 0; int l = 0, r = rotateArray.size() - 1; int mid = l; while(rotateArray[l] >= rotateArray[r]) { if(r - l == 1) { mid = r; break; } mid = (l + r) >> 1; if(rotateArray[l] == rotateArray[mid] && rotateArray[mid] == rotateArray[r]) { int ans = INT_MAX; for(int i = l; i <= r; ++i) ans = min(ans, rotateArray[i]); return ans; } if(rotateArray[l] <= rotateArray[mid]) l = mid; else if(rotateArray[mid] <= rotateArray[r]) r = mid; } return rotateArray[mid]; } };
试题12:矩阵中的路径
简单的dfs,从二维矩阵的每个点进行一次dfs,和目标串尝试进行匹配写了两个稍有不同的写法
写法一:
class Solution { public: bool hasPath(char* matrix, int rows, int cols, char* str) { vector<bool> vis(rows * cols, 0); for(int i = 0; i < rows; ++i) for(int j = 0; j < cols; ++j) { if(matrix[i*cols+j] == *str) { vis[i*cols+j] = true; if(dfs(matrix, rows, cols, str+1, i, j, vis)) return true; vis[i*cols+j] = false; } } return false; } bool dfs(char *matrix, int rows, int cols, char *str, int x, int y, vector<bool> &vis) { int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0}; if(*str == '\0') return true; for(int i = 0; i < 4; ++i) { int nx = x + dx[i], ny = y + dy[i]; if(nx >= 0 && nx < rows && ny >= 0 && ny < cols && vis[nx*cols+ny] == false && matrix[nx*cols+ny] == *str) { vis[nx*cols+ny] = true; if(dfs(matrix, rows, cols, str+< 115f6 span class="hljs-number">1, nx, ny, vis)) return true; vis[nx*cols+ny] = false; } } return false; } };
写法二:
class Solution { public: bool hasPath(char* matrix, int rows, int cols, char* str) { vector<bool> vis(rows * cols, 0); for(int i = 0; i < rows; ++i) for(int j = 0; j < cols; ++j) if(dfs(matrix, rows, cols, str, i, j, vis)) return true; return false; } bool dfs(char *matrix, int rows, int cols, char *str, int x, int y, vector<bool> &vis) { int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0}; if(matrix[x*cols+y] != *str) return false; if(*(str+1) == '\0') return true; vis[x*cols+y] = true; for(int i = 0; i < 4; ++i) { int nx = x + dx[i], ny = y + dy[i]; if(nx >= 0 && nx < rows && ny >= 0 && ny < cols && vis[nx*cols+ny] == false) { if(dfs(matrix, rows, cols, str+1, nx, ny, vis)) return true; } } vis[x*cols+y] = false; return false; } };
试题13:机器人的运动范围
一个简单的bfsclass Solution { public: int movingCount(int threshold, int rows, int cols) { int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};//用来控制从当前位置向上下左右移动 using pii = pair<int, int>; queue<pii> que; vector<bool> vis(rows*cols, 0); int ans = 0; if(decompose(0) + decompose(0) <= threshold) { que.emplace(pii(0, 0)); vis[0*cols+0] = true; ++ans; } while(! que.empty()) { pii p = que.front(); que.pop(); for(int i = 0; i < 4; ++i) { int nx = p.first + dx[i], ny = p.second + dy[i]; if(nx >= 0 && nx < rows && ny >= 0 && ny < cols && vis[nx*cols+ny] == false && decompose(nx) + decompose(ny) <= threshold) { que.emplace(pii(nx, ny)); vis[nx*cols+ny] = true; ++ans; } } } return ans; } int decompose(int n) { int ans = 0; while(n) { ans += n % 10; n /= 10; } return ans; } };
试题14:剪绳子
绳子长度为2、3的时候特判。之后,让剪出的绳子尽可能的长度为3,如果最后绳子长度剩余为1,那么应该和倒数第二段绳子合在一起,剪成两个长度为2的更优class Solution { public: int getMaxProduct(int length) { if(length < 2) return 0; if(length == 2) return 1; if(length == 3) return 2; int num3 = length / 3; if(length - num3 * 3 == 1) --num3; int num2 = (length - num3*3) / 2; int ans = 1; for(int i = 0; i < num2; ++i) ans *= 2; for(int i = 0; i < num3; ++i) ans *= 3; return ans; } };
试题15:二进制中1的个数
谨记负数在内存中的表示方式,负数左移补0,右移补1。解法一:用一个变量初始化为1,每次左移1位与数字进行 & 运算,判断当前位置是否为1
class Solution { public: int NumberOf1(int n) { int f = 1; int cnt = 0; int tot = 32; while(tot--) { if(n & f) ++cnt; f <<= 1; } return cnt; } };
解法二:很巧妙,每次令n = n & (n-1),这样每次去掉最右边的二进制1,记录循环次数即可
class Solution { public: int NumberOf1(int n) { int cnt = 0; while(n) { ++cnt; n = n & (n-1); } return cnt; } };
试题16:数值的整数次方
偷懒直接用pow就好,或者用牛顿迭代法是更好的选择,这里按照书上写的class Solution { public: double Power(double base, int exponent) { const double eps = 1e-8; if(exponent == 0) return 1; if(fabs(base - 0) < eps)//此处,当base=0且exponent<0是无解的,这里也返回了0,牛客里应该没有这样的数据 return 0; double ans = fast_power(base, abs(exponent)); if(exponent < 0) ans = 1.0 / ans; return ans; } double fast_power(double base, int exponent) { double ans = 1.0; while(exponent) { if(exponent & 1) ans *= base; exponent >>= 1; base *= base; } return ans; } };
试题17:打印从1到最大的n位数
这个题牛客上面没有,自己写了一下,模拟一个大整数每次加上1,这里大整数的储存方式从左到右依次为从低位到高位,输出的时候要倒着输出class Solution { public: void Print1ToMaxOfDigits(int n) { if(n == 0) return; int len = n + 1; char *str = new char[len]; for(int i = 0; i < len; ++i) str[i] = '0'; int tot = 1;//大整数的长度 while(true) { int val = 1; for(int i = 0; i < len && val != 0; ++i) { val += str[i]-'0'; str[i] = val%10 + '0'; val /= 10; tot = max(tot, i+1); } if(tot-1 == n)//长度比n大的时候,结束循环 break; for(int i = tot-1; i >= 0; --i) printf("%c", str[i]); printf("\n"); } delete [] str; } };
另外一种解法,用数字排列的方式
class Solution { public: void Print1ToMaxOfDigits(int n) { if(n <= 0) return; char *numbers = new char[n+1]; numbers = '\0'; for(int i = 0; i < 10; ++i) { numbers[0] = i + '0'; dfs(numbers, n, 1); } delete [] numbers; } private: void dfs(char *numbers, int len, int index) { if(index == len) { while(*numbers == '0' && *numbers != '\0')//去掉前导0 ++numbers; if(*numbers != '\0') printf("%s\n", numbers); return; } for(int i = 0; i < 10; ++i) { numbers[index] = i + '0'; dfs(numbers, len, index+1); } } };
试题18:删除链表的节点
这道题牛客上也没有,自己写了一下,主要考虑一下情况:要删除节点就是第一个节点时,那么把头往后面移一位即可
要删除节点就是尾节点时,那么从头遍历找到它的前驱,把前驱置为尾节点
否则,把要删除节点的下一个节点的值赋给要删除节点,把要删除节点的指向它后继的后继,那么此时要删除节点就和它的后继相当于完成了交换,删除它的后继即可,即O(1)删除
另外注意链表为空的情况
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ //主题代码 class Solution { public: ListNode* deleteNode(ListNode* pHead, ListNode *pDeleted) { if(pHead == nullptr) return nullptr; if(pDeleted == nullptr) return pHead; if(pHead == pDeleted) pHead = pHead->next; else { if(pDeleted->next != nullptr) { ListNode *ptr = pDeleted; pDeleted = pDeleted->next; ptr->val = ptr->next->val; ptr->next = ptr->next->next; } else { ListNode *ptr = pHead; while(ptr->next != pDeleted) ptr = ptr->next; ptr->next = nullptr; } } delete pDeleted; return pHead; } }; /* //以下为测试部分 //逆序生成链表 pair<ListNode*, ListNode*> work() { ListNode *pHead = nullptr; ListNode *pDeleted = nullptr; for(int i = 1; i <= 1; ++i) { ListNode *ptr = new ListNode(i); ptr->next = pHead; pHead = ptr; if(i == 1) pDeleted = pHead; } return make_pair(pHead, pDeleted); } //打印链表 void print(ListNode *pHead) { while(pHead != nullptr) { printf("%d ", pHead->val); pHead = pHead->next; } puts(""); } */
删除链表中重复的节点
例如 2 3 3 5 6 6 7,结果应该是 2 5 7
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { if(pHead == nullptr) return nullptr; ListNode *pNode = pHead, *preNode = nullptr; while(pNode != nullptr) { ListNode *temp = pNode; while(pNode->next != nullptr && pNode->val == pNode->next->val) pNode = pNode->next; if(temp != pNode) { pNode = pNode->next; if(preNode == nullptr) pHead = pNode; else preNode->next = pNode; while(temp != pNode) { ListNode *p = temp; temp = temp->next; delete p; } } else { preNode = pNode; pNode = pNode->next; } } return pHead; } };
试题19:正则表达式匹配
用递归求解,注意细节class Solution { public: bool match(char* str, char* pattern) { if(str == nullptr || pattern == nullptr) return false; return dfs(str, pattern); } private: bool dfs(char *str, char *pattern) { if(*str != '\0' && *pattern == '\0') return false; if(*str == '\0' && *pattern == '\0') return true; if(*(pattern+1) == '*') { if((*pattern == '.' && *str != '\0') || *pattern == *str) return dfs(str+1, pattern+2) || dfs(str, pattern+2) || dfs(str+1, pattern); else return dfs(str, pattern+2); } else { if((*pattern == '.' && *str != '\0') || *pattern == *str) return dfs(str+1, pattern+1); else return false; } } };
试题20:表示数值的字符串
剑指offer上的写法很好,注意细节class Solution { public: bool isNumeric(char* string) { if(string == nullptr) return false; bool flag = scanInt(string); if(*string == '.') { ++string; flag = scanUnsignInt(string) || flag; } if(*string == 'e' || *string == 'E') { ++string; flag = scanInt(string) && flag; } return flag && *string == '\0'; } private: bool scanInt(char* &str) { if(*str == '+' || *str == '-') ++str; return scanUnsignInt(str); } bool scanUnsignInt(char* &str) { char *temp = str; while(*str != '\0' && isdigit(*str)) ++str; return str != temp; } };
相关文章推荐
- 剑指offer 11-20
- 【刷题笔记/剑指Offer】Part 2 (11-20)
- 剑指offer--简易动态规划(3、10、20、26,61)
- 剑指Offer----面试题11:数值的整数次方
- 【剑指Offer】鸟瞰50题之11 - 20题
- 【剑指offer】题目20 顺时针打印矩阵
- 剑指offer——面试题11:数值的整数次方
- 剑指offer--11.数值的整数次方
- 剑指Offer面试题11 & Leetcode50
- 剑指Offer:面试题11 数值的整数次方
- 剑指offer_面试题11 数值的整数次方_考察代码的完整性
- 剑指offer代码解析——面试题11求a的b次方
- 剑指offer-面试题20:顺时针打印矩阵
- 剑指Offer面试题11数值的整数次方
- 剑指Offer20 栈的压入弹出序列是否正确
- [剑指offer]面试题20:顺时针打印矩阵
- 剑指Offer----面试题20:顺时针打印矩阵
- 剑指Offer试题总结
- 【面试题】剑指Offer-20-顺时针打印矩阵
- 剑指offer_面试题20_顺时针打印矩阵(思路在一步步分解之中)