⭐️我叫恒心,一名喜欢书写博客的研究生在读生。
原创不易~转载麻烦注明出处
注意:
- 博文是自己在学习的过程记录的笔记,水平有限,读者阅读时请慎重阅读。
- 欢迎转载,著名出处就可以啦。
- 如果帮到你,麻烦三连,关注一下呗。
面试题27 二叉树的镜像
描述
操作给定的二叉树,将其变换为源二叉树的镜像。
比如: 源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
示例1
输入:
{8,6,10,5,7,9,11}
返回值:
{8,10,6,11,9,7,5}
考虑递归和循环来实现
画图后发现其实就是 先序遍历然后交换节点
{8,7,#,6,#,5,#,4}
{8,#,7,#,6,#,5,#,4}
{8,7,#,6,#,5,#,4}
运行时间:4ms超过29.67% 用C++提交的代码
占用内存:480KB超过24.79%用C++提交的代码
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pRoot TreeNode类
* @return TreeNode类
*/
TreeNode* Mirror(TreeNode* pRoot) {
if(pRoot == nullptr)
return pRoot;
// 通过前序遍历 交换各个不为空的子节点
if(pRoot->left==nullptr && pRoot->right==nullptr)
return pRoot;
TreeNode* temp = pRoot->left;
pRoot->left = pRoot->right;
pRoot->right = temp;
// 前序遍历
if(pRoot->left!=nullptr)
Mirror(pRoot->left);
if(pRoot->right!=nullptr)
Mirror(pRoot->right);
return pRoot;
}
};
面试题28 对称的二叉树
描述
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
运行时间:3ms超过33.54% 用C++提交的代码
占用内存:536KB超过22.76%用C++提交的代码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot) {
// 空的也是对称的
// if(pRoot == nullptr)
// return false;
return isSymmetrical(pRoot,pRoot);
}
bool isSymmetrical(TreeNode* lRoot, TreeNode* rRoot){
if(lRoot == nullptr && rRoot == nullptr)
return true;
if(lRoot == nullptr || rRoot == nullptr)
return false;
if(lRoot->val != rRoot->val)
return false;
// 从左到右的遍历和从右到转的遍历一样 则这个二叉树的对称的
return isSymmetrical(lRoot->left, rRoot->right)
&& isSymmetrical(lRoot->right, rRoot->left);
}
};
先序遍历和后续遍历
并不是很懂他的原理 怎么就先序 ->建议做完这一章去看看书,后面刷完K哥的算法笔记再重新刷一下这道题
面试题 29 顺时针打印矩阵
书本上的写法判断太麻烦了。
本科实验室考核的算法啊,书上的代码作为分析思路即可,不容易写出来。
改进的算法
运行时间:3ms
占用内存:524KB
[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int> result;
if(matrix[0].empty() || matrix.empty())
return result;
// 向右 下 左 上 四个方向保存顺序数字
int row = 0, rows = matrix.size()-1;
int col = 0, cols = matrix[0].size()-1;
// 没有一个合适的终止条件 可以借助Break
while(1){
//从左到右
for (int i = col; i <=cols ;++i) result.push_back(matrix[row][i]);
// 如果超出了边界就结束循环
if ( ++row > rows ) break;
// 从上到下
for( int i = row; i <= rows; ++i ) result.push_back(matrix[i][cols]);
if ( --cols < col ) break;
// 从右到左
for( int i= cols; i >= col; i--) result.push_back(matrix[rows][i]);
if ( --rows < row ) break;
// 从下到上
for( int i = rows; i >= row; i--) result.push_back(matrix[i][col]);
if ( ++col > cols) break;
}
return result;
}
};
面试30 包含Min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,并且调用 min函数、push函数 及 pop函数 的时间复杂度都是 O(1)
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
class Solution {
public:
void push(int value) {
s.push(value);
// 如果min栈为空 则直接压栈
if(min_s.empty())
min_s.push(value);
else if(value < min_s.top()){
min_s.push(value);
}else{
min_s.push(min_s.top());
}
}
void pop() {
s.pop();
min_s.pop();
}
int top() {
return s.top();
}
int min() {
return min_s.top();
}
private:
std::stack<int> s;
std::stack<int> min_s;
};
面试题31 栈的压入和弹出序列
描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
借助栈
运行时间:3ms
占用内存:528KB
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
// 定义一个栈 当栈顶的元素和序列的元素相等则弹出
stack<int> s1;
int j=0;
for(int i=0; i<pushV.size();){
s1.push(pushV[i++]);
while(!s1.empty() &&s1.top() == popV[j]){
s1.pop();
++j;
}
}
if(j == popV.size())
return true;
return false;
}
};
参考秀个的算法刷题笔记里面有一个用容器去实现的。
用vector 后面补上
面试题32 从上到下打印二叉树的过程
运行时间:4ms
占用内存:668KB
描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
输入:
{5,4,#,3,#,2,#,1}
返回值:
[5,4,3,2,1]
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
// 用队列来存储 并完成打印操作
vector<int> result;
queue<TreeNode* > q;
if(root == nullptr)
return result;
q.push(root);
TreeNode* node = nullptr;
// 遍历树将每个节点的左右子树存起来
while(q.size()){
node = q.front();
// 取出队列得先进去元素
result.push_back(node->val);
//
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
q.pop();
}
return result;
}
};
把二叉树打印成多行
????新的知识: std::move
- C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了,通过std::move,可以避免不必要的拷贝操作。
std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
对指针类型的标准库对象并不需要这么做。- std::move函数可以以非常简单的方式将左值引用转换为右值引用。(左值 右值 引用 左值引用)概念
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int>> PrintFromTopToBottom(TreeNode* root) {
// 用队列来存储 并完成打印操作
vector<vector<int>> result;
queue<TreeNode* > q;
if(root == nullptr)
return result;
q.push(root);
TreeNode* node = nullptr;
// 遍历树将每个节点的左右子树存起来
while(q.size()){
int size = q.size();
vector<int> temp;
while(size--){
node = q.front();
temp.push_back(node->val);
if(node->left)
q.push(node->left);
if(node->right)
q.push(node->right);
}
result.push_back(temp);
}
return std::move(result);
}
};
之字行打印二叉树
描述
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:
给定的二叉树是{1,2,3,#,#,4,5}
该二叉树之字形层序遍历的结果是
[
[1],
[3,2],
[4,5]
]
运行时间:6ms超过1.54% 用C++提交的代码
占用内存:600KB超过18.85%用C++提交的代码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
if (pRoot == nullptr)
return result;
stack<TreeNode*> left_right_st;
stack<TreeNode*> right_left_st;
left_right_st.push(pRoot);
// 左右两个栈的节点为空的时候结束
while(left_right_st.size() || left_right_st.size()){
if(!left_right_st.empty()){
vector<int> temp;
TreeNode* node;
while(!left_right_st.empty()){
node = left_right_st.top();
temp.push_back(node->val);
// 先左边再右
if(node->left)
right_left_st.push(node->left);
if(node->right)
right_left_st.push(node->right);
left_right_st.pop();
}
result.push_back(temp);
}
if(!right_left_st.empty()){
vector<int> temp;
TreeNode* node;
while(!right_left_st.empty()){
node = right_left_st.top();
temp.push_back(node->val);
// 先左边再右
if(node->right)
left_right_st.push(node->right);
if(node->left)
left_right_st.push(node->left);
right_left_st.pop();
}
result.push_back(temp);
}
}
return result;
}
};
运行时间是个玄学的东西
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
if (pRoot == nullptr)
return result;
stack<TreeNode*> left_right_st;
stack<TreeNode*> right_left_st;
TreeNode* node = nullptr;
left_right_st.push(pRoot);
// 左右两个栈的节点为空的时候结束
while(left_right_st.size() || left_right_st.size()){
if(!left_right_st.empty()){
vector<int> temp;
while(!left_right_st.empty()){
node = left_right_st.top();
temp.push_back(node->val);
left_right_st.pop();
// 先左边再右
if(node->left)
right_left_st.push(node->left);
if(node->right)
right_left_st.push(node->right);
}
result.push_back(std::move(temp));
}
if(!right_left_st.empty()){
vector<int> temp;
TreeNode* node;
while(!right_left_st.empty()){
node = right_left_st.top();
temp.push_back(node->val);
right_left_st.pop();
// 先左边再右
if(node->right)
left_right_st.push(node->right);
if(node->left)
left_right_st.push(node->left);
}
result.push_back(std::move(temp));
}
}
return result;
}
};