二叉树面试题

1. 求二叉树中的节点个数

递归解法:
(1)如果二叉树为空,节点个数为0
(2)如果二叉树不为空,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1
参考代码如下:

def GetNodeNum(root):
    if not root:
        return 0
    return GetNodeNum(root.left)+GetNodeNum(root.right)+1
int GetNodeNum(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL) // 递归出口  
        return 0;  
    return GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1;  
}

2. 求二叉树的深度

递归解法:
(1)如果二叉树为空,二叉树的深度为0
(2)如果二叉树不为空,二叉树的深度 = max(左子树深度, 右子树深度) + 1
参考代码如下:

def GetDepth(root):
    if not root:
        return 0
    return max(GetDepth(root.left),GetDepth(root.left))+1
int GetDepth(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL) // 递归出口  
        return 0;  
    int depthLeft = GetDepth(pRoot->m_pLeft);  
    int depthRight = GetDepth(pRoot->m_pRight);  
    return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);   
}

3. 前序遍历,中序遍历,后序遍历

前序遍历递归解法:
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树
参考代码如下:

def PreOrderTraverse(root):
    if not root:
        return
    visit(root)
    PreOrderTraverse(root.left)
    PreOrderTraverse(root.right)
void PreOrderTraverse(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return;  
    Visit(pRoot); // 访问根节点  
    PreOrderTraverse(pRoot->m_pLeft); // 前序遍历左子树  
    PreOrderTraverse(pRoot->m_pRight); // 前序遍历右子树  
}

中序遍历递归解法
(1)如果二叉树为空,空操作。
(2)如果二叉树不为空,中序遍历左子树,访问根节点,中序遍历右子树
参考代码如下:

def InOrderTraverse(root):
    if not root:
        return
    InOrderTraverse(root.left)
    visit(root)
    IneOrderTraverse(root.right)
void InOrderTraverse(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return;  
    InOrderTraverse(pRoot->m_pLeft); // 中序遍历左子树  
    Visit(pRoot); // 访问根节点  
    InOrderTraverse(pRoot->m_pRight); // 中序遍历右子树  
}

后序遍历递归解法
(1)如果二叉树为空,空操作
(2)如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点
参考代码如下:

def PostOrderTraverse(root):
    if not root:
        return
    PostOrderTraverse(root.left)
    PostOrderTraverse(root.right)
    visit(root)
void PostOrderTraverse(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return;  
    PostOrderTraverse(pRoot->m_pLeft); // 后序遍历左子树  
    PostOrderTraverse(pRoot->m_pRight); // 后序遍历右子树  
    Visit(pRoot); // 访问根节点  
}

4.分层遍历二叉树(按层次从上往下,从左往右)

《编程之美》原题

首先考虑“输出第n层所有节点”,可以用递归解决

#根节点在第0层
def LevelTraverse(root,level):
    if not root or level<0:
        return 0
        #为什么要返回0?见AllLevelTraverse程序
    if(level==0):
        visit(root)
        return 1
    return LevelTraverse(root.left,level-1)+LevelTraverse(root.right,level-1)
//根节点在第0层
int LevelTraverse(BinaryTreeNode * pRoot,int level)
{
    if(!root||level<0)
        return 0
    if(level==0)
    {
        cout << root -> data << " ";
        return 1
    }
    return LevelTraverse(pNode->m_pLeftlevel-1)+LevelTraverse(pNode->m_pLeft,level-1)

层次遍历的最终程序为

def AllLevelTraverse(root):
    level=0
    while(1):
        if not LevelTraverse(root,level):
            break
        level+=1

但是这么做每次都要从根开始,效率很低

在访问第k层的时候,我们只要知道第k-1层的信息就足够了

def PrintNodeByLevel(root):
    cur,last=0,1
    vec=[root]
    while(cur<len(vec)):
        last=len(vec)
        while(cur<last):
            visit(vec[cur])
            if vec[cur].left:
                vec.append(vec[cur].left
            if vec[cur].right:
                vec.append(vec[cur].right
            cur+=1
void PrintNodeByLevel(Node* root) {
     vector<Node*> vec; // 这里我们使用STL 中的vector来代替数组,可利用到其动态扩展的属性
     vec.push_back(root);
     int cur = 0;
     int last = 1;
     while(cur < vec.size()) {
          Last = vec.size(); // 新的一行访问开始,重新定位last于当前行最后一个节点的下一个位置
          while(cur < last) {
               cout << vec[cur] -> data << " "; // 访问节点
               if(vec[cur] -> lChild) // 当前访问节点的左节点不为空则压入
                   vec.push_back(vec[cur] -> lChild);
               if(vec[cur] -> rChild) // 当前访问节点的右节点不为空则压入,注意左右节点的访问顺序不能颠倒
                   vec.push_back(vec[cur] -> rChild);
               cur++;
          }
          cout << endl; // 当cur == last时,说明该层访问结束,输出换行符
     }
}

相当于广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点,访问,若左子节点或右子节点不为空,将其压入队列。

void LevelTraverse(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return;  
    queue<BinaryTreeNode *> q;  
    q.push(pRoot);  
    while(!q.empty())  
    {  
        BinaryTreeNode * pNode = q.front();  
        q.pop();  
        Visit(pNode); // 访问节点  
        if(pNode->m_pLeft != NULL)  
            q.push(pNode->m_pLeft);  
        if(pNode->m_pRight != NULL)  
            q.push(pNode->m_pRight);  
    }  
    return;  
}

非层次遍历

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: A Tree
    @return: Level order a list of lists of integer
    """
    def levelOrder(self, root):
        # write your code here
        if not root:
            return []
        
        father=[root]
        son=[]
        res=[]
        
        while(father):
            tmp_res=[]
            for node in father:
                if(node):
                    tmp_res.append(node.val)
                    son.append(node.left)
                    son.append(node.right)
            if(tmp_res):
                res.append(tmp_res)
            #print(res)
            father=son
            son=[]
            
        return res
            

5. 将二叉查找树变为有序的双向链表

要求不能创建新节点,只调整指针。

递归解法:

(1)如果二叉树查找树为空,不需要转换,对应双向链表的第一个节点是NULL,最后一个节点是NULL

(2)如果二叉查找树不为空:
如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;

如果左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,同时将根节点和左子树转换后的双向有序链表的最后一个节点连接;

如果右子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作;

如果右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点,同时将根节点和右子树转换后的双向有序链表的第一个节点连接。


class Solution:
    # @param root: a TreeNode, the root of the binary tree
    # @return: nothing
    def flatten(self, root):
        # write your code here
        if root == None:
            return
        self.flatten(root.left)
        self.flatten(root.right)
        p = root
        if p.left == None:
            return
        p = p.left
        while p.right:
            p = p.right
        p.right = root.right
        root.right = root.left
        root.left = None
/*
参数: 
pRoot: 二叉查找树根节点指针 
pFirstNode: 转换后双向有序链表的第一个节点指针 
pLastNode: 转换后双向有序链表的最后一个节点指针 
*/  
void Convert(BinaryTreeNode * pRoot,   
             BinaryTreeNode * & pFirstNode, BinaryTreeNode * & pLastNode)  
{  
    BinaryTreeNode *pFirstLeft, *pLastLeft, * pFirstRight, *pLastRight;  
    if(pRoot == NULL)   
    {  
        pFirstNode = NULL;  
        pLastNode = NULL;  
        return;  
    }  
  
    if(pRoot->m_pLeft == NULL)  
    {  
        // 如果左子树为空,对应双向有序链表的第一个节点是根节点  
        pFirstNode = pRoot;  
    }  
    else  
    {  
        Convert(pRoot->m_pLeft, pFirstLeft, pLastLeft);  
        // 二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点  
        pFirstNode = pFirstLeft;  
        // 将根节点和左子树转换后的双向有序链表的最后一个节点连接  
        pRoot->m_pLeft = pLastLeft;  
        pLastLeft->m_pRight = pRoot;  
    }  
  
    if(pRoot->m_pRight == NULL)  
    {  
        // 对应双向有序链表的最后一个节点是根节点  
        pLastNode = pRoot;  
    }  
    else  
    {  
        Convert(pRoot->m_pRight, pFirstRight, pLastRight);  
        // 对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点  
        pLastNode = pLastRight;  
        // 将根节点和右子树转换后的双向有序链表的第一个节点连接  
        pRoot->m_pRight = pFirstRight;  
        pFirstRight->m_pLeft = pRoot;  
    }  
  
    return;  
}

6. 求二叉树第K层的节点个数

递归解法:

  • (1)如果二叉树为空或者k<1返回0
  • (2)如果二叉树不为空并且k==1,返回1
  • (3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和
#根节点在第0层
def LevelTraverse(root,level):
    if not root or level<0:
        return 0
        #为什么要返回0?见AllLevelTraverse程序
    if(level==0):
        visit(root)
        return 1
    return LevelTraverse(root.left,level-1)+LevelTraverse(root.right,level-1)
int GetNodeNumKthLevel(BinaryTreeNode * pRoot, int k)  
{  
    if(pRoot == NULL || k < 1)  
        return 0;  
    if(k == 1)  
        return 1;  
    int numLeft = GetNodeNumKthLevel(pRoot->m_pLeft, k-1); // 左子树中k-1层的节点个数  
    int numRight = GetNodeNumKthLevel(pRoot->m_pRight, k-1); // 右子树中k-1层的节点个数  
    return (numLeft + numRight);  
}

7. 求二叉树中叶子节点的个数

递归解法:
(1)如果二叉树为空,返回0
(2)如果二叉树不为空且左右子树为空,返回1
(3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
参考代码如下:

def countNode(root):
    if not root:
        return 0
    return countNode(root.left)+countNode(root.right)+1
int GetLeafNodeNum(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return 0;  
    if(pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL)  
        return 1;  
    int numLeft = GetLeafNodeNum(pRoot->m_pLeft); // 左子树中叶节点的个数  
    int numRight = GetLeafNodeNum(pRoot->m_pRight); // 右子树中叶节点的个数  
    return (numLeft + numRight);  
}

8. 判断两棵二叉树是否结构相同

不考虑数据内容。结构相同意味着对应的左子树和对应的右子树都结构相同。

递归解法:

  1. 如果两棵二叉树都为空,返回真
  2. 如果两棵二叉树一棵为空,另一棵不为空,返回假
  3. 如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假

参考代码如下:

def treecmp(root1,root2):
    if (not root1) and (not root2):
        return True
    if root1 or root2:
        return False
    return treecmp(root1.left,root2.left) and treecmp(root1.right,root2.right)
bool StructureCmp(BinaryTreeNode * pRoot1, BinaryTreeNode * pRoot2)  
{  
    if(pRoot1 == NULL && pRoot2 == NULL) // 都为空,返回真  
        return true;  
    else if(pRoot1 == NULL || pRoot2 == NULL) // 有一个为空,一个不为空,返回假  
        return false;  
    bool resultLeft = StructureCmp(pRoot1->m_pLeft, pRoot2->m_pLeft); // 比较对应左子树   
    bool resultRight = StructureCmp(pRoot1->m_pRight, pRoot2->m_pRight); // 比较对应右子树  
    return (resultLeft && resultRight);  
}

9. 判断二叉树是不是平衡二叉树

递归解法:

  • (1)如果二叉树为空,返回真
  • (2)如果二叉树不为空,如果左子树和右子树都是AVL树并且左子树和右子树高度相差不大于1,返回真,其他返回假
def getH(root):
    if not root:
        return 0
    return max(getH(root.left),getH(root.right))+1

def isBalanced(root):
    if not root:
        return True
    diff=getH(root.left)-getH(root.right)
    if abs(diff)>1:
        return False
    else:
        return isBalanced(root.left) and isBalanced(root.right)

虽然可行,但是效率不太高,因为getH会被反复调用计算同一个结点的高度。我们可以如下的改进

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def f(self,root):
        if root is None:
            return True,0
        flag,leftheight=self.f(root.left)
        if not flag:
            return False,0
        flag,rightheight=self.f(root.left)
        if not flag:
            return False,0
        return abs(leftheight-rightheight)<2, max(leftheight, rightheight) + 1
    
    def IsBalanced_Solution(self, pRoot):
        # write code here
        flag,height=self.f(pRoot)
        return flag

10. 求二叉树的镜像

递归解法:

  • (1)如果二叉树为空,返回空
  • (2)如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树

参考代码如下:

def mirror(root):
    if not root:
        return
    left=mirror(root.left)
    right=mirror(root.right)
    root.left=right
    root.right=left
    return root
BinaryTreeNode * Mirror(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL) // 返回NULL  
        return NULL;  
    BinaryTreeNode * pLeft = Mirror(pRoot->m_pLeft); // 求左子树镜像  
    BinaryTreeNode * pRight = Mirror(pRoot->m_pRight); // 求右子树镜像  
        // 交换左子树和右子树  
    pRoot->m_pLeft = pRight;  
    pRoot->m_pRight = pLeft;  
    return pRoot;  
}

11. 求二叉树中两个节点的最低公共祖先节点

递归解法:

  • (1)如果两个节点分别在根节点的左子树和右子树,则返回根节点
  • (2)如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树
bool FindNode(BinaryTreeNode * pRoot, BinaryTreeNode * pNode)  
{  
    if(pRoot == NULL || pNode == NULL)  
        return false;  
  
    if(pRoot == pNode)  
        return true;  
  
    bool found = FindNode(pRoot->m_pLeft, pNode);  
    if(!found)  
        found = FindNode(pRoot->m_pRight, pNode);  
  
    return found;  
}  
  
BinaryTreeNode * GetLastCommonParent(BinaryTreeNode * pRoot,BinaryTreeNode * pNode1,BinaryTreeNode * pNode2)  
{  
    if(FindNode(pRoot->m_pLeft, pNode1))  
    {  
        if(FindNode(pRoot->m_pRight, pNode2))  
            return pRoot;  
        else  
            return GetLastCommonParent(pRoot->m_pLeft, pNode1, pNode2);  
    }  
    else  
    {  
        if(FindNode(pRoot->m_pLeft, pNode2))  
            return pRoot;  
        else  
            return GetLastCommonParent(pRoot->m_pRight, pNode1, pNode2);  
    }  
}

递归解法效率很低,有很多重复的遍历,下面看一下非递归解法。

非递归解法:

先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点也就是他们在二叉树中的最低公共祖先节点

bool GetNodePath(BinaryTreeNode * pRoot, BinaryTreeNode * pNode,   
                 list<BinaryTreeNode *> & path)  
{  
    if(pRoot == pNode)  
    {     
        path.push_back(pRoot);  
        return true;  
    }  
    if(pRoot == NULL)  
        return false;  
    path.push_back(pRoot);  
    bool found = false;  
    found = GetNodePath(pRoot->m_pLeft, pNode, path);  
    if(!found)  
        found = GetNodePath(pRoot->m_pRight, pNode, path);  
    if(!found)  
        path.pop_back();  
    return found;  
}  
BinaryTreeNode * GetLastCommonParent(BinaryTreeNode * pRoot, BinaryTreeNode * pNode1, BinaryTreeNode * pNode2)  
{  
    if(pRoot == NULL || pNode1 == NULL || pNode2 == NULL)  
        return NULL;  
    list<BinaryTreeNode*> path1;  
    bool bResult1 = GetNodePath(pRoot, pNode1, path1);  
    list<BinaryTreeNode*> path2;  
    bool bResult2 = GetNodePath(pRoot, pNode2, path2);  
    if(!bResult1 || !bResult2)   
        return NULL;  
    BinaryTreeNode * pLast = NULL;  
    list<BinaryTreeNode*>::const_iterator iter1 = path1.begin();  
    list<BinaryTreeNode*>::const_iterator iter2 = path2.begin();  
    while(iter1 != path1.end() && iter2 != path2.end())  
    {  
        if(*iter1 == *iter2)  
            pLast = *iter1;  
        else  
            break;  
        iter1++;  
        iter2++;  
    }  
    return pLast;  
}

在上述算法的基础上稍加变化即可求二叉树中任意两个节点的距离了。

12. 求二叉树中节点的最大距离

即二叉树中相距最远的两个节点之间的距离。

递归解法:

  • (1)如果二叉树为空,返回0,同时记录左子树和右子树的深度,都为0
  • (2)如果二叉树不为空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,要么是左子树节点中到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。
int GetMaxDistance(BinaryTreeNode * pRoot, int & maxLeft, int & maxRight)  
{  
    // maxLeft, 左子树中的节点距离根节点的最远距离  
    // maxRight, 右子树中的节点距离根节点的最远距离  
    if(pRoot == NULL)  
    {  
        maxLeft = 0;  
        maxRight = 0;  
        return 0;  
    }  
    int maxLL, maxLR, maxRL, maxRR;  
    int maxDistLeft, maxDistRight;  
    if(pRoot->m_pLeft != NULL)  
    {  
        maxDistLeft = GetMaxDistance(pRoot->m_pLeft, maxLL, maxLR);  
        maxLeft = max(maxLL, maxLR) + 1;  
    }  
    else  
    {  
        maxDistLeft = 0;  
        maxLeft = 0;  
    }  
    if(pRoot->m_pRight != NULL)  
    {  
        maxDistRight = GetMaxDistance(pRoot->m_pRight, maxRL, maxRR);  
        maxRight = max(maxRL, maxRR) + 1;  
    }  
    else  
    {  
        maxDistRight = 0;  
        maxRight = 0;  
    }  
    return max(max(maxDistLeft, maxDistRight), maxLeft+maxRight);  
}

13. 由前序遍历序列和中序遍历序列重建二叉树

二叉树前序遍历序列中,第一个元素总是树的根节点的值。中序遍历序列中,左子树的节点的值位于根节点的值的左边,右子树的节点的值位于根节点的值的右边。

递归解法:

  • (1)如果前序遍历为空或中序遍历为空或节点个数小于等于0,返回NULL。
  • (2)创建根节点。前序遍历的第一个数据就是根节点的数据,在中序遍历中找到根节点的位置,可分别得知左子树和右子树的前序和中序遍历序列,重建左右子树。
BinaryTreeNode * RebuildBinaryTree(int* pPreOrder, int* pInOrder, int nodeNum)  
{  
    if(pPreOrder == NULL || pInOrder == NULL || nodeNum <= 0)  
        return NULL;  
    BinaryTreeNode * pRoot = new BinaryTreeNode;  
    // 前序遍历的第一个数据就是根节点数据  
    pRoot->m_nValue = pPreOrder[0];  
    pRoot->m_pLeft = NULL;  
    pRoot->m_pRight = NULL;  
    // 查找根节点在中序遍历中的位置,中序遍历中,根节点左边为左子树,右边为右子树  
    int rootPositionInOrder = -1;  
    for(int i = 0; i < nodeNum; i++)  
        if(pInOrder[i] == pRoot->m_nValue)  
        {  
            rootPositionInOrder = i;  
            break;  
        }  
    if(rootPositionInOrder == -1)  
    {  
        throw std::exception("Invalid input.");  
    }  
    // 重建左子树  
    int nodeNumLeft = rootPositionInOrder;  
    int * pPreOrderLeft = pPreOrder + 1;  
    int * pInOrderLeft = pInOrder;  
    pRoot->m_pLeft = RebuildBinaryTree(pPreOrderLeft, pInOrderLeft, nodeNumLeft);  
    // 重建右子树  
    int nodeNumRight = nodeNum - nodeNumLeft - 1;  
    int * pPreOrderRight = pPreOrder + 1 + nodeNumLeft;  
    int * pInOrderRight = pInOrder + nodeNumLeft + 1;  
    pRoot->m_pRight = RebuildBinaryTree(pPreOrderRight, pInOrderRight, nodeNumRight);  
    return pRoot;  
}

同样,有中序遍历序列和后序遍历序列,类似的方法可重建二叉树,但前序遍历序列和后序遍历序列不同恢复一棵二叉树,证明略。
14.判断二叉树是不是完全二叉树
若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全
二叉树。
有如下算法,按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,则该节点右子树必须为空,且后面遍历的节点左
右子树都必须为空,否则不是完全二叉树。

bool IsCompleteBinaryTree(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL)  
        return false;  
    queue<BinaryTreeNode *> q;  
    q.push(pRoot);  
    bool mustHaveNoChild = false;  
    bool result = true;  
    while(!q.empty())  
    {  
        BinaryTreeNode * pNode = q.front();  
        q.pop();  
        if(mustHaveNoChild) // 已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)  
        {  
            if(pNode->m_pLeft != NULL || pNode->m_pRight != NULL)  
            {  
                result = false;  
                break;  
            }  
        }  
        else  
        {  
            if(pNode->m_pLeft != NULL && pNode->m_pRight != NULL)  
            {  
                q.push(pNode->m_pLeft);  
                q.push(pNode->m_pRight);  
            }  
            else if(pNode->m_pLeft != NULL && pNode->m_pRight == NULL)  
            {  
                mustHaveNoChild = true;  
                q.push(pNode->m_pLeft);  
            }  
            else if(pNode->m_pLeft == NULL && pNode->m_pRight != NULL)  
            {  
                result = false;  
                break;  
            }  
            else  
            {  
                mustHaveNoChild = true;  
            }  
        }  
    }  
    return result;  
}

14 二叉树所有路径

从根节点出发找叶子,找到叶子之后,所有这条“找寻之路”上的所有节点构成了我们要打印出来的一条路径。所以,我们需要建立一个全局变量path,存储未到达当前节点时扫描过的路径中有哪些节点,作为从当前节点起,往叶子遍历所经过的路径的前缀。同理,最后的结果列表也是一个全局变量了。
所以,当题目中给出的函数形参只有一个root时,我们就需要再设定一个辅助函数,包含刚才说的path和result,让他们两个成为全局变量。
总结一下思路:

  1. 建立一个字符串变量path和结果列表result,初始化为空
  2. 从根节点开始访问,之后访问其左子树,再访问其右子树
  3. 每访问一个节点,将节点的值加入path,例如,访问完根节点后,path = “1 ->”,并将这里的path作为新的变量加入左右子树的遍历函数
  4. 递归“触底”的条件:访问的节点为空
    思路:
    二叉树遍历问题
    如果当前节点的左儿子和右儿子都为None => 说明当前节点为一个根节点,输出一条路径
    如果当前节点有左儿子,带着path向左进行。如果有右儿子,带着path向右进行
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def binaryTreePaths(self, root):
        """
        :type root: TreeNode
        :rtype: List[str]
        """
        def helper(root,path,res):
            if root.left is None and root.right is None:
                res.append(path+str(root.val))
                return 
            if root.left:
                helper(root.left, path + str(root.val)+'->', res)
            if root.right:
                helper(root.right, path + str(root.val)+'->', res)

        if root is None:
            return []
        l = []
        self.helper(root, '', l)
        return l

15 二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果
在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        if not pNode:
            return pNode
        if pNode.right:
            left1=pNode.right
            while left1.left:
                   left1=left1.left
            return left1
        p=pNode
        while pNode.next:
            tmp=pNode.next
            if tmp.left==pNode:
                return tmp
            pNode=tmp

16 二叉树的序列化与反序列化

设计一个算法,并编写代码来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”。

如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构。

样例
样例 1:

输入:{3,9,20,#,#,15,7}
输出:{3,9,20,#,#,15,7}
解释:
二叉树 {3,9,20,#,#,15,7},表示如下的树结构:
	  3
	 / \
	9  20
	  /  \
	 15   7
它将被序列化为 {3,9,20,#,#,15,7}
样例 2:

输入:{1,2,3}
输出:{1,2,3}
解释:
二叉树 {1,2,3},表示如下的树结构:
   1
  / \
 2   3
它将被序列化为 {1,2,3}
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    flag = -1
    def Serialize(self, root):
        s = ""
        s = self.recursionSerialize(root, s)
        return s
 
    def recursionSerialize(self, root, s):
        if (root is None):
            s = '$,'
            return s
        s = str(root.val) + ','
        left = self.recursionSerialize(root.left, s)
        right = self.recursionSerialize(root.right, s)
        s += left + right
        return s
 
    def Deserialize(self, s):
        self.flag += 1
        l = s.split(',')
        if (self.flag >= len(s)):
            return None
        root = None
        if (l[self.flag] != '$'):
            root = TreeNode(int(l[self.flag]))
            root.left = self.Deserialize(s)
            root.right = self.Deserialize(s)
        return root

17 二叉树中和为某一值的路径

输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return []
        if root and not root.left and not root.right and root.val == expectNumber:
            return [[root.val]]
        res = []
        left = self.FindPath(root.left, expectNumber-root.val)
        right = self.FindPath(root.right, expectNumber-root.val)
        for i in left+right:
            res.append([root.val]+i)
        return res
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值