⭐️我叫恒心,一名喜欢书写博客的研究生在读生。

原创不易~麻烦注明出处



注意:

  • 博文是自己在学习的过程记录的笔记,水平有限,读者阅读时请慎重阅读。
  • 欢迎转载,著名出处就可以啦。
  • 如果帮到你,麻烦三连,关注一下呗。

面试题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}

C++牛客网剑指Offer学习笔记(三)_牛客网

该二叉树之字形层序遍历的结果是

[

[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;
}

};