马上要面试了,把前些天在剑指Offer上刷的题再看一遍。
写上注释,算复习了,也方便以后复习。
带 * 号的为忘记怎么做的。
1. 二维数组中的查找(数组优化)
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int row_num = array.size();
if (row_num == 0) return false;
int col_num = array[0].size();
// 从左下角开始找
int i = row_num - 1, j = 0;
while (i >= 0 && j < col_num) {
// 对于每个位置有3种情况
if (array[i][j] == target) return true;
else if (array[i][j] > target) i--;
else j++;
}
// 越过边界仍未找到
return false;
}
};
/*
class Solution {
public:
int binarySearch(vector<int> arr, int target) {
// 二分查找,找到返回索引,否则返回-1
int left = 0, right = arr.size() - 1;
int mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) left ++;
else right --;
}
return -1;
}
bool Find(int target, vector<vector<int> > array) {
int row_num = array.size();
if (row_num == 0) return false;
int col_num = array[0].size();
for (int i = 0; i < row_num; i++) {
// 对每1行执行二分查找
if (binarySearch(array[i], target) != -1)
return true;
}
return false;
}
};
*/
2. 替换空格(字符串模拟)
class Solution {
public:
// 从后向前处理,降低数组元素移动的复杂度
void replaceSpace(char *str, int length) {
int count = 0;
// 统计空格数
for (int i = 0; i < length; i++)
if (str[i] == ' ')
count++;
// 从后向前
for (int i = length - 1; i >= 0; i--) {
// 不为空格,向后移
if (str[i] != ' ')
str[i + 2 * count] = str[i];
// 为空格,处理,并使剩余空格减一
if (str[i] == ' ') {
str[i + 2 * count - 2] = '%';
str[i + 2 * count - 1] = '2';
str[i + 2 * count] = '0';
count--;
}
}
}
};
3. 从尾到头打印链表(链表模拟)
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
// 先执行字符串翻转
ListNode *pre = NULL, *cur = head, *post;
while (cur != NULL) {
// 翻转需要这4步
post = cur->next;
cur->next = pre;
pre = cur;
cur = post;
}
vector<int> ans;
// 再将翻转后的1各个压入
while (pre != NULL) {
ans.push_back(pre->val);
pre = pre->next;
}
return ans;
}
};
4*. 重建二叉树(二叉树)
class Solution {
public:
TreeNode* Create(vector<int> pre, int &preIndex, vector<int> mid, int left, int right) {
// pre: 前序遍历序列
// preIndex: 前序遍历的根节点索引
// mid: 中序遍历序列
// left: 当前中序序列的最左侧索引
// right: 当前中序序列的最右侧索引
if (left > right) return NULL; // 当前序列没有结点,直接返回NULL
TreeNode *root = new TreeNode(pre[preIndex++]); // 建立根节点
// 在中序遍历序列中找到根节点的索引
int i;
for (i = left; i <= right; i++) if (mid[i] == root->val) break;
// 递归建立左右子树
root->left = Create(pre, preIndex, mid, left, i - 1);
root->right = Create(pre, preIndex, mid, i + 1, right);
return root;
}
TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
int preIndex = 0;
return Create(pre, preIndex, vin, 0, pre.size() - 1);
}
};
5. 用两个栈实现队列
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
// 当stack2为空时,将stack1中的元素送入到stack2中
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
// 总是从stack2中取元素返回
int ret = stack2.top();
stack2.pop();
return ret;
}
private:
stack<int> stack1;
stack<int> stack2;
};
6. 旋转数组的最小数字(二分搜索)
class Solution {
public:
int minNumberInRotateArray(vector<int> arr) {
if (arr.size() == 0) return 0;
int left = 0, right = arr.size() - 1;
while (left < right) {
// 每次都要检查当前序列是否是被翻转的,如果没有,则返回最左侧
if (arr[left] < arr[right]) return arr[left];
int mid = left + (right - left) / 2;
// 说明mid位置处于前方子序列
if (arr[mid] > arr[left]) left = mid + 1;
// 说明mid位置处于后方子序列,最小元素在后方子序列,所以不能mid-1
else if (arr[mid] < arr[left]) right = mid;
// 如果相等,则需要遍历,如1111011
else left ++;
}
return arr[left];
}
};
7. 斐波那契数列(模拟)
class Solution {
public:
int Fibonacci(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
int temp = 0, sum = 1;
// 更优化的写法
// 如 0 1 1 2 3 5 8 13 21
for (int i = 2; i <= n; i++) {
sum += temp, temp = sum - temp;
}
return sum;
}
};
8. 跳台阶(动态规划)
class Solution {
public:
int jumpFloor(int number) {
if (number <= 1) return number;
int temp = 1, sum = 1;
// 更优化的写法
// 1 1 2 3 5 8 13 21
// 算第i时,sum存的是i-1处的和,temp存的是i-2处的值
// 算完,通过运算,sum存i处的和,temp存i-1处的值
for (int i = 2; i <= number; i++) {
sum += temp, temp = sum - temp;
}
return sum;
}
};
9. 变态跳台阶(动态规划)
class Solution {
public:
int jumpFloorII(int number) {
// 最优解:
// 因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
// 跳1级,剩下n-1级,则剩下跳法是f(n-1)
// 跳2级,剩下n-2级,则剩下跳法是f(n-2)
// 所以f(n)=f(n-1)+f(n-2)+...+f(1)
// 因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
// 所以f(n)=2*f(n-1)
// return 1 << (number - 1);
// 初始为从0级一次性到各个位置的方式数,为1
vector<int> count(number + 1, 1);
// i位置的方式数为由[1...i-1]位置一次性到达的方式之和
for (int i = 2; i <= number; i++) {
for (int j = 1; j <= i - 1; j++) {
count[i] += count[j];
}
}
return count[number];
}
};
10. 矩形覆盖(递归)
class Solution {
public:
int rectCover(int number) {
if (number == 0) return 0;
if (number == 1) return 1;
if (number == 2) return 2;
// 每次要么横着放2个,要么竖着放1个
return rectCover(number - 1) + rectCover(number - 2);
}
};
来源:CSDN
作者:dmxjhg
链接:https://blog.csdn.net/liujh_990807/article/details/104085449