2020.2 刷题笔记
剑指offer https://www.nowcoder.com/ta/coding-interviews?page=1
11-20
- 二进制中1的个数
- 数值的整数次方
- 调整数组顺序使奇数位于偶数前面
- 链表中倒数第k个结点
- 反转链表
- 合并两个排序的链表
- 树的子结构
- 二叉树的镜像
- 顺时针打印矩阵
- 包含min函数的栈
-
二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
class Solution { public: int NumberOf1(int n) { int n1 = abs(n), count = 0, total = 0; bool flag = false; for (;n1;n1 /= 2) { //依次得到从右往左数每一数位的数码 ++total; int tmp = n1 % 2; if (n > 0 && tmp == 1) ++count; else if (n < 0) { if (tmp == 1) flag = true; if (tmp == 0 && flag) ++count; } } if (n < 0) count += 32 - total + 1; return count; } };
- 注意该题中二进制表示是32位的
- 正数补码=原码,负数补码=反码+1,即对负数来说,从右往左数第一个1的左边是反码,右边是原码
-
数值的整数次方
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0
class Solution { public: double Power(double base, int exponent) { if (exponent == 0) return 1.; else { double result = base; for (int i = 2;i <= abs(exponent);++i) result *= base; if (exponent < 0) result = 1 / result; return result; } } };
- 别写成 base *= base
- 易漏考虑 exponent < 0 的情况
-
调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
class Solution { public: void reOrderArray(vector<int> &array) { vector<int> newArray; for (int i = 0;i < array.size();++i) { if (array[i] % 2 == 1) newArray.push_back(array[i]); } for (int i = 0;i < array.size();++i) { if (array[i] % 2 == 0) newArray.push_back(array[i]); } array = newArray; } };
-
链表中倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { ListNode *p = pListHead, *q = pListHead; for (int i = 0;i < k;++i) { if (p == NULL) return NULL; p = p->next; } for (;p != NULL;p = p->next, q = q->next); return q; } };
注意k大于本身链表长度的情况
-
反转链表
输入一个链表,反转链表后,输出新链表的表头。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* ReverseList(ListNode* pHead) { ListNode* newHead = NULL; for (ListNode* p = pHead;p != NULL;) { ListNode* tmp = p->next; p->next = newHead; newHead = p; p = tmp; } return newHead; } };
-
合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { ListNode *p1 = pHead1, *p2 = pHead2, *pHead3 = NULL, *p3 = NULL; for (;p1 != NULL && p2 != NULL;) { if (p1->val <= p2->val) { if (pHead3 == NULL) pHead3 = p3 = p1; else { p3->next = p1; p3 = p3->next; } p1 = p1->next; } else { if (pHead3 == NULL) pHead3 = p3 = p2; else { p3->next = p2; p3 = p3->next; } p2 = p2->next; } } if (p3 != NULL) p1 != NULL ? p3->next = p1 : p3->next = p2; else p1 != NULL ? pHead3 = p1 : pHead3 = p2; return pHead3; } };
注意输入链表可能为空的情况
-
树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool SubHas(TreeNode* pRoot1, TreeNode* pRoot2) { if (pRoot2 == NULL) return true; else if (pRoot1 == NULL) return false; if (pRoot1->val != pRoot2->val) return false; else return (SubHas(pRoot1->left, pRoot2->left) && SubHas(pRoot1->right, pRoot2->right)); } bool Has(TreeNode* pRoot1, TreeNode* pRoot2) { if (pRoot1->val == pRoot2->val && SubHas(pRoot1, pRoot2)) return true; if (pRoot1->left != NULL && Has(pRoot1->left, pRoot2)) return true; if (pRoot1->right != NULL && Has(pRoot1->right, pRoot2)) return true; return false; } bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { if (pRoot1 == NULL || pRoot2 == NULL) return false; else return Has(pRoot1, pRoot2); } };
注意区分子树和子结构
测试用例1:{8,8,7,9,2,#,#,#,#,4,7},{8,9,2}
8 8 7 9 2 # # # # 4 7
-
二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。输入描述:
二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ 11 9 7 5
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: void Mirror(TreeNode *pRoot) { if (pRoot == NULL) return; Mirror(pRoot->left); Mirror(pRoot->right); TreeNode *tmp = pRoot->left; pRoot->left = pRoot->right; pRoot->right = tmp; } };
-
顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
class Solution { public: vector<int> printMatrix(vector<vector<int> > matrix) { const int dx[] = {0, 1, 0, -1}; const int dy[] = {1, 0, -1, 0}; int row = matrix.size(), col = matrix[0].size(); int size = row * col; --row; vector<int> printm(size, 0); for (int i = 0, j = -1, count = 0, d = 0;count < size;--row, --col) { for (int k = 0;k < col && count < size;++k) { j += dy[d]; printm[count++] = matrix[i][j]; } d = (d + 1) % 4; for (int k = 0;k < row && count < size;++k) { i += dx[d]; printm[count++] = matrix[i][j]; } d = (d + 1) % 4; } return printm; } };
有很多细节要注意
-
包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
class Solution { public: void push(int value) { s.push(value); ++mp[value]; } void pop() { int top = s.top(); s.pop(); --mp[top]; } int top() { //if (s.empty()) return -1; return s.top(); } int min() { //if (s.empty()) return -1; map<int, int>::iterator iter = mp.begin(); for (;iter != mp.end() && iter->second <= 0;++iter); return iter->first; } stack<int> s; map<int, int>mp; };