专项练习
任何数据结构与算法技巧的熟悉都需要我们一定题目量的训练。训练最终达到的目的是下意识的把我们见到的陌生的题目转换为我们做过的题目类型。
我希望小伙伴们刻意的按照下面的步骤去思考:
(1)分析提取题目特征
(2)遍历数据结构,先判断哪几种数据结构与题目描述符合
(3)遍历算法思想与技巧,看看原题目是否可以通过转换变为我们熟悉的题目。
二叉树
二叉树的非递归遍历(先根序、中根序、后根序)
深度优先遍历的非递归实现一般都会借助栈,先根序与中根序的实现模式比较接近,后根序稍微复杂一些。
144. Binary Tree Preorder Traversal 先根序遍历
使用到的辅助数据结构:vector、stack
使用到的算法思想:深度优先遍历的非递归
//先根序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> p;
while(root || !p.empty())
{
//从根节点开始遇到左子树就开始入栈,一直到叶子节点
while(root)
{
p.push(root);
result.push_back(root->val);
root = root->left;
}
//弹出当前结点
root = p.top();
p.pop();
//开始遍历右子树
root = root->right;
}
return result;
}
};
还是以左子树的遍历为例,流程入下:
(1)左子树一直入栈,直到叶子结点
(2)4出栈
(3)4没有右子树,2继续出栈,2有右子树5,5没有左子树
(4)1出栈
94. Binary Tree Inorder Traversal 中根序遍历
中根序遍历使用到的数据结构与算法思想与先根序一致,所不同是root-value的放入时机
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> p;
while(root || !p.empty())
{
//从根节点开始遇到左子树就开始入栈,一直到叶子节点
while(root)
{
p.push(root);
root = root->left;
}
//弹出当前结点
root = p.top();
p.pop();
result.push_back(root->val);
//开始遍历右子树
root = root->right;
}
return result;
}
};
145. Binary Tree Postorder Traversal 后根序遍历
后根序使用的数据结构与算法仍旧与前序、中序相同,但程序结构略有不同,原因是后根序需要在遍历完左、右子树后再访问一次根结点。所以需要额外保留一个指针变量记录上次访问的结点。
先看代码
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> p;
TreeNode* root1 = root;
TreeNode* preNode = nullptr;
do
{
//同样从根结点开始一直把左子树入栈,直到叶子结点
while(root1)
{
p.push(root1);
root1 = root1->left;
}
//使用preNode 保留上次访问的结点,用来判断当前root结点是否是访问完右结点的root结点
preNode = nullptr;
while(!p.empty())
{
root1 = p.top();
p.pop();
//如果已经访问完了右结点,则当前root结点可以放入result中
if(root1->right == preNode)
{
result.push_back(root1->val);
preNode = root1;
}
//如果root结点没有右结点或者还没访问过右结点,则继续入栈
else{
p.push(root1);
root1 = root1->right;
break;
}
}
}while(!p.empty());
return result;
}
};
以下面二叉树中的245结点为例说明上面程序流程,我们已经以1为根结点已经遍历到了最左边的叶子结点4
102. Binary Tree Level Order Traversal 二叉树的层序遍历
使用到的辅助数据结构:vector、queue
使用到的算法思想:广度优先遍历的非递归和递归
//递归
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int> > res;
levelorder(root,0,res);
return res;
}
void levelorder(TreeNode* root, int level, vector<vector<int> >& res)
{
if(!root)
return;
if(res.size() == level)
res.push_back({});
res[level].push_back(root->val);
if(root->left)
levelorder(root->left,level+1,res);
if(root->right)
levelorder(root->right,level+1,res);
}
};
//非递归
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int> >res;
if(root == NULL)
return res;
queue<TreeNode*> q;
q.push(root);
while(!q.empty())
{
vector<int> oneLevel;
int size = q.size();
for(int i = 0; i <size; ++i)
{
TreeNode *node = q.front();
q.pop();
oneLevel.push_back(node->val);
if(node->left)
q.push(node->left);
if(node->right)
q.push(node->right);
}
res.push_back(oneLevel);
}
return res;
}
};
怎样应对IT面试与笔试-(一)
怎样应对IT面试与笔试-(二)
怎样应对IT面试与笔试-(三)
怎样应对IT面试与笔试-(四)
怎样应对IT面试与笔试-(五)
怎样应对IT面试与笔试-(五-1)
怎样应对IT面试与笔试-(六)
怎样应对IT面试与笔试-(七)
怎样应对IT面试与笔试-(八)
怎样应对IT面试与笔试-(九)
怎样应对IT面试与笔试-(十)
怎样应对IT面试与笔试-(十一)
怎样应对IT面试与笔试-(十二)
怎样应对IT面试与笔试-(十三)
怎样应对IT面试与笔试-(十四)
怎样应对IT面试与笔试-(十五)
怎样应对IT面试与笔试-(十六)