61.序列化二叉树
class Solution {
private:
string SerializeCore(TreeNode* root) {
if (root == nullptr) {
return "#!"; // !表示一个结点值的结束
}
string str;
str = to_string(root->val) + "!";
str += SerializeCore(root->left);
str += SerializeCore(root->right);
return str;
}
TreeNode* DeserializeCore(char*& str) {
if (*str == '#') {
str++;
return nullptr;
}
int num = 0;
while (*str != '!') { // 当出现字符 ‘123!’,可以转换为int
num = num * 10 + *str - '0';
str++;
}
TreeNode* node = new TreeNode(num);
node->left = DeserializeCore(++str);
node->right = DeserializeCore(++str);
return node;
}
public:
char* Serialize(TreeNode* root) {
string str = SerializeCore(root);
char* res = new char[str.size()];
for (int i = 0; i < str.size(); i++) {
res[i] = str[i];
}
return res;
}
TreeNode* Deserialize(char* str) {
return DeserializeCore(str);
}
};
62.二叉搜索树的第k个节点
class Solution {
vector<int> vec;
public:
void LDR(TreeNode* root) {
if (!root) return;
LDR(root->left);
vec.push_back(root->val);
LDR(root->right);
}
int KthNode(TreeNode* proot, int k) {
LDR(proot);
if (0 == k || k > vec.size()) return -1;
return vec[k - 1];
}
};
63.数据流中的中位数
使用容器,然后排序
class Solution {
public:
vector<int> vec;
void Insert(int num) {
vec.push_back(num);
}
double GetMedian() {
sort(vec.begin(), vec.end());
int len = vec.size();
if (len % 2 == 1) {
return double(vec[len / 2]);
} else {
return double(vec[len / 2] + vec[(len - 1) / 2]) / 2;
}
}
};
将其插入的所有数字看成一个集合,由大到小排列,然后左侧使用大顶堆,右侧使用小顶堆,这样就可以根据元素个数始终知道中位值,如果为奇数个,中位值就为大顶堆的top,如果为偶数个,中位值为大顶堆的top与小顶堆top的平均值
class Solution {
public:
int count = 0;
priority_queue<int, vector<int>, less<int>> left_big; // 大顶锥, 降序排列, top指向大值,位于左侧
priority_queue<int, vector<int>, greater<int>> right_small; // 小顶锥, 升序排列, top指向小值,位于右侧
void Insert(int num) {
count++;
if (count % 2 == 1) {
right_small.push(num);
left_big.push(right_small.top());
right_small.pop();
} else {
left_big.push(num);
right_small.push(left_big.top());
left_big.pop();
}
}
double GetMedian() {
if (count % 2 == 1) return left_big.top();
else {
return (left_big.top() + right_small.top()) / 2.0;
}
}
};
64.滑动窗口的最大值
暴力循环
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size) {
int len = num.size();
if (size > len || len == 0 || size == 0) return vector<int>();
vector<int> ans;
int cnt = len - size + 1;
for (int i = 0; i < cnt; i++) {
int maxNum = INT_MIN;
for (int j = i; j < i + size; j++) {
if (num[j] > maxNum) maxNum = num[j];
}
ans.push_back(maxNum);
}
return ans;
}
};
双向队列
思路:
我们都知道,若是一个数字A进入窗口后,若是比窗口内其他数字都大,那么这个数字之前的数字都没用了,因为它们必定会比A早离开窗口,在A离开之前都争不过A,所以A在进入时依次从尾部排除掉之前的小值再进入,而每次窗口移动要弹出窗口最前面值,因此队首也需要弹出,所以我们选择双向队列。
具体做法:
step 1:维护一个双向队列,用来存储数列的下标。
step 2:首先检查窗口大小与数组大小。
step 3:先遍历第一个窗口,如果即将进入队列的下标的值大于队列后方的值,依次将小于的值拿出来去掉,再加入,保证队列是递增序。
step 4:遍历后续窗口,每次取出队首就是最大值,如果某个下标已经过了窗口,则从队列前方将其弹出。
step 5:对于之后的窗口,重复step 3,直到数组结束。
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size) {
int len = num.size();
if (size > len || len == 0 || size == 0) return vector<int>();
vector<int> ans;
deque<int> dq; // 维护一个双向队列,用来存储数列的下标
for (int i = 0; i < len; i++) {
// 去掉比自己先进队列的小于自己的值
while (!dq.empty() && num[dq.back()] < num[i]) {
dq.pop_back();
}
dq.push_back(i);
// 判断队列的头部的下标是否不在窗口范围
if (dq.front() + size <= i) {
dq.pop_front();
}
// 判断是否形成了窗口
if (i + 1 >= size) {
ans.push_back(num[dq.front()]);
}
}
return ans;
}
};
65.矩阵中的路径
DFS
class Solution {
public:
bool DFS(vector<vector<char>>& board, char* str, int index, int x, int y,
vector<vector<bool>>& visited)
{
if (index == strlen(str)) return true;
if ((x < 0) || (y < 0) || (x >= board.size()) || (y >= board[0].size())) return false;
if (visited[x][y]) return false;
if (board[x][y] != str[index]) return false;
visited[x][y] = true;
if (DFS(board, str, index + 1, x, y - 1, visited) || //上
DFS(board, str, index + 1, x, y + 1, visited) || //下
DFS(board, str, index + 1, x - 1, y, visited) || //左
DFS(board, str, index + 1, x + 1, y, visited)) //右
return true; // 有符合要求的
visited[x][y] = false; // 如果没有符合要求的,需要从新遍历搜索,改回false
return false;
}
bool hasPath(char* matrix, int rows, int cols, char* str)
{
if (str == nullptr || rows <= 0 || cols <= 0) return false;
vector<vector<char>> board(rows, vector<char>(cols));
// 将字符串装入二维数组中
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
board[i][j] = matrix[i * cols + j];
}
}
vector<vector<bool>> visited(rows, vector<bool>(cols, false));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (DFS(board, str, 0, i, j, visited) == true) return true;
}
}
return false;
}
};
66.机器人的运动范围
class Solution {
public:
int cnt = 0;
int cal(int n) {
int sum = 0;
while (n) {
sum += (n % 10);
n /= 10;
}
return sum;
}
void DFS(int i, int j, int rows, int cols,
int threshold, vector<vector<bool> >& visited) {
// 越界访问
if (i < 0 || j < 0 || i >= rows || j >= cols) return;
// 已经访问过
if (visited[i][j]) return;
// 不符合要求
if (cal(i) + cal(j) > threshold) return;
cnt += 1;
visited[i][j] = true;
// 上下左右
DFS(i + 1, j, rows, cols, threshold, visited);
DFS(i - 1, j, rows, cols, threshold, visited);
DFS(i, j - 1, rows, cols, threshold, visited);
DFS(i, j + 1, rows, cols, threshold, visited);
}
int movingCount(int threshold, int rows, int cols) {
if (rows < 0 || cols < 0) return 0;
vector<vector<bool>> visited(rows, vector<bool>(cols, false));
DFS(0, 0, rows, cols, threshold, visited);
return cnt;
}
};
67.剪绳子
4 : 2+2
5 : 2+3
6 : 3+3
7 : 2+2+3 或者4+3
8 : 2+3+3
9 : 3+3+3
10:2+2+3+3 或者4+3+3
分析后可以推出,最大乘积划分后 只有2和3,所以主要求出要分别划分为多少个2和3
class Solution {
public:
int cutRope(int number) {
if (number == 2) return 1;
if (number == 3) return 2;
int x = number % 3;
int y = number / 3;
if (x == 0) return pow(3, y);
else if (x == 1) return 2 * 2 * pow(3, y - 1); // 看成有两个2, y-1个3 而不是 y个3,1个1
else return 2 * pow(3, y); // 一个2,y个3
}
};
class Solution {
public:
int cutRope(int number) {
if (number == 2) return 1;
if (number == 3) return 2;
int maxNum=1;
while(number>4){
maxNum*=3;
number-=3;
}
maxNum*=number;
return maxNum;
}
};