* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
與二叉樹相關(guān)的代碼有大量的指針操作,在每次使用指針的時(shí)候,需要判斷指針是否是nullptr,以及該如何處理。
【面試題06:重建二叉樹】
題目:輸入某二叉樹的前序遍歷和中序遍歷的結(jié)果,請(qǐng)重建出該二叉樹。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復(fù)的數(shù)字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹并返回。
思路:根據(jù)前序找到根節(jié)點(diǎn),然后在中序中找到左右根序列,遞歸。采用vector裝序列,即每次遞歸更新前序vector和中序vector。如果是python,可利用list的切片。
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.empty() || vin.empty()) return nullptr;
vector<int>left_pre,left_vin,right_vin,right_pre;
int rootValue = pre[0];
//創(chuàng)建根節(jié)點(diǎn)
TreeNode* root = new TreeNode(rootValue);
int m = 0;
while(m+1<vin.size() && vin[m] != rootValue){
left_pre.push_back(pre[m+1]);
left_vin.push_back(vin[m]);
m++;
} //更新左子樹的前序、中序。
while(m+1<vin.size()){
right_pre.push_back(pre[m+1]);
right_vin.push_back(vin[m+1]);
m++;
}//更新右子樹的前序和中序
//重建左子樹
root->left = reConstructBinaryTree(left_pre,left_vin);
//重建右子樹
root->right = reConstructBinaryTree( right_pre,right_vin);
//返回重建二叉樹
return root;
}
};
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回構(gòu)造的TreeNode根節(jié)點(diǎn)
def reConstructBinaryTree(self, pre, tin):
if len(pre) == 0 or len(tin) == 0:
return None
root = TreeNode(pre[0])
m = 0
#找到中序中根節(jié)點(diǎn)的位置m
while tin[m] != pre[0]:
m += 1
##利用list的切片,直接更新左右子樹前序、中序
root.left = self.reConstructBinaryTree(pre[1:m+1],tin[:m])
root.right = self.reConstructBinaryTree(pre[m+1:],tin[m+1:])
return root
【面試題58:二叉樹的下一個(gè)結(jié)點(diǎn)】
題目:給定一個(gè)二叉樹和其中的一個(gè)結(jié)點(diǎn),請(qǐng)找出中序遍歷順序的下一個(gè)結(jié)點(diǎn)并且返回。注意,樹中的結(jié)點(diǎn)不僅包含左右子結(jié)點(diǎn),同時(shí)包含指向父結(jié)點(diǎn)的指針。
思路:分兩種情況:1)節(jié)點(diǎn)存在右子樹;2)不存在右子樹,又分兩種:a)遍歷父節(jié)點(diǎn),能找到父節(jié)點(diǎn)的左子節(jié)點(diǎn)是本身的節(jié)點(diǎn);b)不存在a)中節(jié)點(diǎn)。
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode == nullptr) return nullptr;
TreeLinkNode* pNext = nullptr;
if(pNode->right != nullptr){
pNext = pNode->right;
while(pNext->left != nullptr)
pNext = pNext->left;
}//情況一:結(jié)點(diǎn)存在右子樹
else if(pNode->next != nullptr){
TreeLinkNode* pParent = pNode;
//情況二:結(jié)點(diǎn)不存在右子樹,并不是根節(jié)點(diǎn)。
//同時(shí)尋找父節(jié)點(diǎn)的左結(jié)點(diǎn)是本身的結(jié)點(diǎn)。
while(pParent->next != nullptr
&& pParent->next->left != pParent)
pParent = pParent->next;
//協(xié)議節(jié)點(diǎn)為該節(jié)點(diǎn)的父節(jié)點(diǎn),如不存在即為根節(jié)點(diǎn)的父節(jié)點(diǎn)nullptr
pNext = pParent->next;
}
return pNext;
}
};
【面試題19:樹的子結(jié)構(gòu)】Subtree of Another Tree
題目:輸入兩棵二叉樹A,B,判斷B是不是A的子結(jié)構(gòu)。(ps:我們約定空樹不是任意一個(gè)樹的子結(jié)構(gòu))。注意題目子結(jié)構(gòu)的定義:1)存在即可;2)存在即左右子樹全部一樣。
思路:兩步:1)找到相同根節(jié)點(diǎn),然后遞歸判斷左右子樹,返回結(jié)果;2)遞歸左右子樹找到下一個(gè)相同根節(jié)點(diǎn)。
####子結(jié)構(gòu)定義:
3
/ \
4 5
/ \
1 2
/
0
Given tree t:
4
/ \
1 2
Return false.
class Solution {
public:
bool isSubtree(TreeNode* s, TreeNode* t) {
if(s == nullptr || t == nullptr) return false;
bool result = false;
if(s->val == t->val)
result = JudgeSubTree(s,t);
if(!result)
result = isSubtree(s->left, t);
if(!result)
result = isSubtree(s->right, t);
return result;
}
bool JudgeSubTree(TreeNode* s, TreeNode* t) {
if(s == nullptr && t == nullptr) return true;
if(t == nullptr || s == nullptr) return false;
if(s->val != t->val) return false;
return JudgeSubTree(s->left,t->left) && JudgeSubTree(s->right, t->right);
}
};
【面試題19:二叉樹的鏡像】
題目:完成一個(gè)函數(shù),輸入一個(gè)二叉樹,該函數(shù)輸出它的鏡像。
思路:左右子樹交換。
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot == nullptr) return;
if(pRoot->left == nullptr && pRoot->right == nullptr)
return ;
TreeNode* temp = pRoot->left;
pRoot->left = pRoot->right;
pRoot->right = temp;
Mirror(pRoot->left);
Mirror(pRoot->right);
}
};
【面試題59:對(duì)稱的二叉樹】
題目:請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù)來判斷一棵二叉樹是不是對(duì)稱的。如果一棵二叉樹和它的鏡像一樣,那么它是對(duì)稱的。
思路:1)求出二叉樹的鏡像,然后判斷是否與原二叉樹相等。具體:將根節(jié)點(diǎn)的左子樹鏡像,然后與右子樹相比。
2)采用遍歷思想,對(duì)稱即左和右可以交換,以前序遍歷為例,根左右和根右左應(yīng)該是相等的。
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
return isSymmetricalTree(pRoot,pRoot);
}
bool isSymmetricalTree(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot1 == nullptr && pRoot2 == nullptr)
return true;
if(pRoot1 == nullptr || pRoot2 == nullptr)
return false;
if(pRoot1->val != pRoot2->val)
return false;
return isSymmetricalTree(pRoot1->left, pRoot2->right)
&& isSymmetricalTree(pRoot1->right, pRoot2->left);
}
};
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root == nullptr || (root->left ==nullptr && root->right == nullptr))
return true;
TreeNode* leftTree = Mirror(root->left);
return isSameTree(leftTree, root->right);
}
###遞歸代碼的理解,如函數(shù)需要返回根節(jié)點(diǎn):
TreeNode* Mirror(TreeNode* pRoot){
if(pRoot == nullptr)
return nullptr;
if(pRoot->left == nullptr && pRoot->right == nullptr)
return pRoot;
TreeNode* temp = pRoot->left;
pRoot->left = Mirror(pRoot->right);
pRoot->right = Mirror(temp);
return pRoot;
}
bool isSameTree(TreeNode* t1, TreeNode* t2){
if(t1 == nullptr && t2 == nullptr)
return true;
if(t1 == nullptr || t2 == nullptr) return false;
if(t1->val != t2->val)
return false;
return isSameTree(t1->left, t2->left) && isSameTree(t1->right, t2->right);
}
};
【面試題23:從上往下打印二叉樹】
題目:從上往下打印出二叉樹的每個(gè)節(jié)點(diǎn),同層節(jié)點(diǎn)從左至右打印。
思路:利用隊(duì)列前出后進(jìn)操作,逐層遍歷push進(jìn)隊(duì)列。
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
if(root == nullptr) return {};
vector<int>result;
deque<TreeNode*>dequeOrder;
dequeOrder.push_back(root);
while(dequeOrder.size()){
TreeNode *curNode = dequeOrder.front();
result.push_back(curNode->val);
dequeOrder.pop_front();
if(curNode->left)
dequeOrder.push_back(curNode->left);
if(curNode->right)
dequeOrder.push_back(curNode->right);
}
return result;
}
};
【面試題24:二叉搜索樹的后序遍歷序列】
題目:輸入一個(gè)整數(shù)數(shù)組,判斷該數(shù)組是不是某二叉搜索樹的后序遍歷的結(jié)果。如果是則輸出Yes,否則輸出No。假設(shè)輸入的數(shù)組的任意兩個(gè)數(shù)字都互不相同。
思路:找出根節(jié)點(diǎn),然后遍歷序列,找到左右子樹,然后遞歸,不滿足條件即返回false。
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
if(sequence.empty()) return false;
int root = sequence[sequence.size()-1];
int i = 0;
vector<int> left,right;
while(i<sequence.size()-1 && sequence[i]<root)
left.push_back(sequence[i++]);
while(i<sequence.size()-1 && sequence[i]>root)
right.push_back(sequence[i++]);
if(i != sequence.size()-1) return false;
bool isLeft = true, isRight = true;
if(!left.empty())
isLeft = VerifySquenceOfBST(left);
if(!right.empty())
isRight = VerifySquenceOfBST(right);
return isLeft && isRight;
}
};
【面試題25:二叉樹中和為某一值的路徑】
題目:輸入一顆二叉樹的跟節(jié)點(diǎn)和一個(gè)整數(shù),打印出二叉樹中結(jié)點(diǎn)值的和為輸入整數(shù)的所有路徑。路徑定義為從樹的根結(jié)點(diǎn)開始往下一直到葉結(jié)點(diǎn)所經(jīng)過的結(jié)點(diǎn)形成一條路徑。
思路:遍歷二叉樹,采用前序,即先訪問根節(jié)點(diǎn)進(jìn)行操作,然后遞歸左右子樹。具體來說:訪問當(dāng)前節(jié)點(diǎn)若為葉節(jié)點(diǎn)且滿足和相等,則打印或push_back,然后遞歸左右子樹。不管怎么樣到達(dá)葉節(jié)點(diǎn),需要pop_back,返回父節(jié)點(diǎn)。
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
vector<vector<int>>pathAll;
if(root == nullptr)
return pathAll;
vector<int>path;
pathFind(root,expectNumber,path,pathAll,0);
return pathAll;
}
void pathFind(TreeNode* root, int sum, vector<int>path,
vector<vector<int>> &pathAll, int curSum){
if(root == nullptr) return ;
curSum += root->val;
path.push_back(root->val);
if(curSum == sum && root->left == nullptr && root->right == nullptr)
pathAll.push_back(path);
pathFind(root->left,sum,path,pathAll,curSum);
pathFind(root->right,sum,path,pathAll,curSum);
path.pop_back();
}
};
【面試題27:二叉搜索樹與雙向鏈表】
題目:輸入一棵二叉搜索樹,將該二叉搜索樹轉(zhuǎn)換成一個(gè)排序的雙向鏈表。要求不能創(chuàng)建任何新的結(jié)點(diǎn),只能調(diào)整樹中結(jié)點(diǎn)指針的指向。
思路:由于是二叉搜索樹,其中序遍歷即為最后鏈表排序順序,然后剩下來的工作就是指針的轉(zhuǎn)換操作。定義一個(gè)指針指向已經(jīng)轉(zhuǎn)好的鏈表的最后一個(gè)節(jié)點(diǎn)。當(dāng)前節(jié)點(diǎn)left指向定義節(jié)點(diǎn),定義節(jié)點(diǎn)right指向當(dāng)前節(jié)點(diǎn),然后定義節(jié)點(diǎn)更新成當(dāng)前節(jié)點(diǎn)。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
ConvertNode(pRootOfTree);
TreeNode* pHead = pNode;
while(pHead != nullptr && pHead->left != nullptr)
pHead = pHead->left;
return pHead;
}
void ConvertNode(TreeNode* pRoot){
if(pRoot != nullptr){
//訪問左子樹
ConvertNode(pRoot->left);
//訪問節(jié)點(diǎn)pRoot,為中序遍歷節(jié)點(diǎn),進(jìn)行指針操作。
pRoot->left = pNode;
if(pNode != nullptr)
pNode->right = pRoot;
pNode = pRoot;
//訪問右子樹
ConvertNode(pRoot->right);
}
}
private:
TreeNode* pNode = nullptr;
};
【面試題60:把二叉樹打印出多行】
【面試題61:按之字形順序打印二叉樹】
【面試題62:序列化二叉樹】
【面試題63:二叉搜索樹的第k個(gè)結(jié)點(diǎn)】
題目:給定一棵二叉搜索樹,請(qǐng)找出其中的第k小的結(jié)點(diǎn)。例如, (5,3,7,2,4,6,8) 中,按結(jié)點(diǎn)數(shù)值大小順序第三小結(jié)點(diǎn)的值為4。
思路:中序遍歷,如果滿足k == 1 則返回此時(shí)節(jié)點(diǎn)。
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
TreeNode* kthNode = nullptr;
InOrder(pRoot,k,&kthNode);
return kthNode;
}
void InOrder(TreeNode* pRoot, int &k, TreeNode** kthNode){
if(pRoot != nullptr){
InOrder(pRoot->left, k, kthNode);
if(k-- == 1){
*kthNode = pRoot;
return ;
}
InOrder(pRoot->right, k, kthNode);
}
}
};
//帶返回值的遞歸
class Solution {
int count = 0; //引入成員變量,如果k是值傳遞的話。
public:
TreeNode* KthNode(TreeNode* pRoot, unsigned int &k)
{//k為引用傳遞
if(pRoot){
TreeNode *ret = KthNode(pRoot->left, k);
if(ret) return ret; // 左子樹找的到第k個(gè),則temp不為nullptr,返回temp
if(--k == 0) return pRoot; // 如果滿足條件,返回proot(不為nullptr)
ret = KthNode(pRoot->right,k);
if(ret) return ret;//同理
}//如果找不到,則一直遍歷,最后返回nullptr。
return nullptr;
}
};
【面試題39:二叉樹的深度】
題目:輸入一棵二叉樹,求該樹的深度。從根結(jié)點(diǎn)到葉結(jié)點(diǎn)依次經(jīng)過的結(jié)點(diǎn)(含根、葉結(jié)點(diǎn))形成樹的一條路徑,最長(zhǎng)路徑的長(zhǎng)度為樹的深度。
拓展:平衡二叉樹的判斷。
思路:深度計(jì)算為左右子樹去較大值+1,進(jìn)而遞歸左右子樹累加深度。判斷平衡二叉樹,不僅需要計(jì)算左右子樹的深度,而且還要判斷是否平衡,返回bool。進(jìn)而增加一個(gè)引用,用于計(jì)算深度,函數(shù)返回是否平衡。
啟發(fā):一個(gè)函數(shù)存在多個(gè)變量需要返回時(shí),可以增加函數(shù)參數(shù)(采用引用傳遞)。
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{//計(jì)算二叉樹深度
if(pRoot == nullptr)
return 0 ;
int depthLeft = TreeDepth(pRoot->left);
int depthRight = TreeDepth(pRoot->right);
return depthLeft>depthRight? depthLeft+1: depthRight+1;
}
//判斷平衡二叉樹
bool IsBalanced_Solution(TreeNode* pRoot) {
int depth = 0;
return IsBalancedTree(pRoot,depth);
}
bool IsBalancedTree(TreeNode* pRoot, int &depth) {
if(pRoot == nullptr){
depth = 0;
return true;
}
int left, right;
if(IsBalancedTree(pRoot->left,left)
&& IsBalancedTree(pRoot->right,right)){
int diff = left -right;
if(diff<=1 && diff>=-1){
depth = left > right ? left+1 : right+1;
return true;
}
}
return false;
}
};