目录
层序遍历(一)
思路
代码
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> arr;
queue<TreeNode*> q;
if(root!=nullptr){
q.push(root);
}
while(!q.empty()){
vector<int> tmp; //存储一层的结点
int size=q.size(); //此时队列内的元素就是上一层的结点个数
for(int i=0;i<size;++i){
tmp.push_back(q.front()->val);
if(q.front()->left){ //有子树就放进队列中
q.push(q.front()->left);
}
if(q.front()->right){
q.push(q.front()->right);
}
q.pop(); //出掉这个父结点
}
arr.push_back(tmp);
}
return arr;
}
层序遍历(二)
思路
代码
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> arr;
queue<TreeNode*> q;
if(root!=nullptr){
q.push(root);
}
while(!q.empty()){
vector<int> tmp;
int size=q.size();
for(int i=0;i<size;++i){
tmp.push_back(q.front()->val);
if(q.front()->left){
q.push(q.front()->left);
}
if(q.front()->right){
q.push(q.front()->right);
}
q.pop();
}
arr.push_back(tmp);
}
reverse(arr.begin(),arr.end()); //逆置
return arr;
}
根据二叉树创建字符串
思路
代码
void front_order(TreeNode* root,string& ans){
if(root==nullptr){
return ;
}
ans+=to_string(root->val);
if(root->left||root->right){
//左需要特殊判断,左右均有/只有右/只有左,都需要打印左,即使是空括号
ans+='(';
front_order(root->left,ans);
ans+=')';
}
if(root->right){ //右只需要在它存在时打印
ans+="(";
front_order(root->right,ans);
ans+=')';
}
}
string tree2str(TreeNode* root) {
string ans;
front_order(root,ans);
return ans;
}
二叉树的最近公共祖先
思路
代码
暴力版
bool find(TreeNode* root, TreeNode* p){
if(root==nullptr){
return false;
}
if(root==p){
return true;
}
return find(root->left,p)||find(root->right,p); //只要一边找到了就返回真
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==nullptr){
return nullptr;
}
if(root==p||root==q){
return root;
}
//判断当前结点下,要找结点的相对位置
bool pleft=find(root->left,p);
bool pright=!pleft;
bool qleft=find(root->left,q);
bool qright=!qleft;
//如果都在左,去左找
if(pleft&&qleft){
return lowestCommonAncestor(root->left,p,q);
}
//如果都在右,去右找
else if(pright&&qright){
return lowestCommonAncestor(root->right,p,q);
}
//走到这里,说明一左一右
else{
return root;
}
}
队列版
bool find_q(TreeNode* root, TreeNode* p,queue<TreeNode*>& ans){
if(root==nullptr){
return false;
}
if(root==p){
ans.push(root); //队列:先入子结点,保证先出的是子结点
return true;
}
if(find_q(root->left,p,ans)){ //为真就存储起来(说明当前结点是路径上的一点)
ans.push(root);
return true;
}
if(find_q(root->right,p,ans)){ //同理
ans.push(root);
return true;
}
return false; //走到这里,说明左右均没找到,就说明这条路没有要找的结点
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
queue<TreeNode*> sp,sq;
find_q(root,p,sp);
find_q(root,q,sq);
//先将多的出掉
while(sp.size()>sq.size()){
sp.pop();
}
while(sp.size()<sq.size()){
sq.pop();
}
//然后同时出,直到找到那个公共结点
while(sp.front()!=sq.front()){
sp.pop();
sq.pop();
}
return sp.front();
}
栈版
bool find_s(TreeNode* root, TreeNode* p,stack<TreeNode*>& ans){
if(root==nullptr){
return false;
}
ans.push(root); //注意:栈必须得先入父结点,保证先出的是子结点
if(root==p){
return true;
}
if(find_s(root->left,p,ans)){
return true;
}
if(find_s(root->right,p,ans)){
return true;
}
ans.pop();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> sp,sq;
find_s(root,p,sp);
find_s(root,q,sq);
while(sp.size()>sq.size()){
sp.pop();
}
while(sp.size()<sq.size()){
sq.pop();
}
while(sp.top()!=sq.top()){
sp.pop();
sq.pop();
}
}
bs树和双向链表
思路
代码
void inorder(TreeNode* root,TreeNode*& prev){
if(root==nullptr){
return;
}
inorder(root->left,prev);
root->left=prev;
if(prev){ //prev会为空,所以需要判断,不然就越界了
prev->right=root;
}
prev=root; //因为之后要进root的后继结点了,所以需要更新prev
inorder(root->right,prev);
}
TreeNode* Convert(TreeNode* pRootOfTree) {
if(pRootOfTree==nullptr){
return nullptr;
}
TreeNode *prev=nullptr,*tmp=pRootOfTree;
while(tmp->left!=nullptr){ //拿到链表的第一个结点
tmp=tmp->left;
}
inorder(pRootOfTree,prev);
return tmp;
}
前序中序序列构建二叉树
思路
代码
class Solution {
public:
TreeNode* _build(vector<int>& preorder, vector<int>& inorder, int& prei, int inbegin, int inend) {
if (inbegin > inend) { //数组不合法,说明不存在这个结点,所以返回空
return nullptr;
}
TreeNode* node = new TreeNode(preorder[prei]); //按照前序构建二叉树(因为先拿到的都是根结点)
int begin = inbegin;
// while(preorder[prei]!=inorder[begin]&&begin<=inend){
// begin++;
// }
for (; begin <= inend; ++begin) { //在中序中找到根结点
if (preorder[prei] == inorder[begin]) {
break;
}
}
++prei; //拿到下一个结点
node->left = _build(preorder, inorder, prei, inbegin, begin - 1);//在找到的根结点,左区间是左子树
node->right = _build(preorder, inorder, prei, begin + 1, inend);//同理
return node;//左右子树构建完毕后,返回该结点
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int prei = 0, inbegin = 0, inend = inorder.size();
TreeNode* root = _build(preorder, inorder, prei, 0, (int)inorder.size() - 1);
//注意这里的prei是引用
return root; //最后返回的就是根结点
}
};
中序后序序列构建二叉树
思路
代码
TreeNode* _build(vector<int>& inorder, vector<int>& postorder,int& posti,int inbegin,int inend){
if(inbegin>inend){
return nullptr;
}
TreeNode* root=new TreeNode(postorder[posti]);
int begin=inbegin;
while(begin<=inend){
if(postorder[posti]==inorder[begin]){
break;
}
begin++;
}
--posti; //注意是--嗷
root->right=_build(inorder,postorder,posti,begin+1,inend);//先被构建的是右子树
root->left=_build(inorder,postorder,posti,inbegin,begin-1);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int posti=postorder.size()-1;
TreeNode* root=_build(inorder,postorder,posti,0,inorder.size()-1);
return root;
}
非递归前序遍历
思路
代码
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ans; //存放前序序列的结点值
stack<TreeNode*> tmp; //存放左结点指针,用于访问其右子树
TreeNode* cur=root;
while(!tmp.empty()||cur){ //栈空+当前结点是空结点,出循环
while(cur){
ans.push_back(cur->val); //入左结点
tmp.push(cur); //存左结点指针
cur=cur->left;
}
TreeNode* top=tmp.top();
cur=top->right; //访问右子树
tmp.pop();
}
return ans;
}
非递归中序遍历
思路
代码
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans; //存放中序序列的结点值
stack<TreeNode*> tmp; //存放左结点指针,用于访问其右子树
TreeNode* cur=root;
while(!tmp.empty()||cur){ //栈空+当前结点是空结点,出循环
while(cur){ //把所有左结点入栈
tmp.push(cur);
cur=cur->left;
}
cur=tmp.top(); //拿取栈顶元素
ans.push_back(cur->val); //入中序序列
cur=cur->right; //访问其右子树
tmp.pop(); //该结点没啥用了,直接出
}
return ans;
}
非递归后序遍历
思路
代码
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ans; //存放中序序列的结点值
stack<TreeNode*> tmp; //存放左结点指针,用于访问其右子树
TreeNode* cur=root,*prev=nullptr;
while(!tmp.empty()||cur){ //栈空+当前结点是空结点,出循环
while(cur){ //把所有左结点入栈(cur就用于把当前结点的左结点存入栈)
tmp.push(cur);
cur=cur->left;
}
TreeNode* top=tmp.top(); //代表当前的根结点
if(top->right==nullptr || top->right==prev){
ans.push_back(top->val); //入后序序列
prev=top; //用于下一次循环时,判断上一个结点的右子树是否被访问过
tmp.pop(); //该结点没啥用了,直接出
}
else{
cur=top->right; //没有被访问过,就去右子树进行循环
}
}
return ans;
}