********二叉树的节点定义*********
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(NULL),right(NULL){}
};
*******二叉树的遍历*****************
1->树的先序遍历
vector<int> preorderTraversal(TreeNode *root){
vector<int> result;
const TreeNode *p;
stack<const TreeNode *> s;
p=root;
if(p!=root) s.push(p);
while(!s.empty()){
p=s.top(); s.pop();
result.push_back(p->val);
if(p->right!=NULL) s.push(p->right);
if(p->left!=NULL) s.push(p->left);
}
return result;
}
2->树的中序遍历
vector<int> inorderTraversal(TreeNode *root){
vector<int> result;
const TreeNode *p=root;
stack<const TreeNode *> s;
while(!s.empty() || p!=NULL){
if(p!=NULL){
s.push(p); p=p->left;
}else{
p=s.top(); s.pop();
result.push_back(p->val);
p=p->right;
}
}
return result;
}
3->树的后续遍历
vector<int> postorderTraversal(TreeNode *root){
vector<int> result;
const TreeNode *p,*q; //p指向正在访问的节点,q指向刚刚访问过的节点
stack<const TreeNode *> s;
p=root;
do{
while(p!=NULL){
s.push(p); p=p->left;
}
q=NULL;
while(!s.empty()){
p=s.top(); s.pop();
if(p->right==q){ //右孩子不存在或者已经访问过了,则访问当前结点
result.push_back(p->val); q=p; //保存刚刚访问过的结点
}else{
/*当前结点不能访问,需要二次进栈*/
s.push(p); p=p->right; break;
}
}
}while(!s.empty());
return result;
}
4->树的层次遍历。例如:BinaryTree{3,9.20,#,#,15,7} 返回的层次遍历【【3】,【9,20】,【15,7】】
vector<vector<int> >levelOrder(TreeNode *root){
vector<vector<int> > result;
if(root==NULL) return result;
queue<TreeNode *>cur,next;
vector<int> level;
cur.push(root);
while(!cur.empty()){
while(!cur.empty()){
TreeNode* node=cur.front(); cur.pop();
level.push(node->val);
if(node->left!=NULL) next.push(node->left);
if(node->right!=NULL) next.push(node->right);
}
result.push_back(level);
level.clear();
swap(next,cur);
}
return result;
}
5->树的层次遍历二:例如:BinaryTree{3,9,20,#,#,15,7} 返回层次遍历【【15,7】,【9,20】,【3】】
解题方法:与上一题类似,将最终的结果反转一下。
6->树的Zigzag层次遍历:例如BinaryTree{3,9,20,#,#,15,7}返回层次遍历【【3】,【20,9】,【15,7】】
解题方法:广度优先遍历,用一个bool记录是从左到右还是从右到左,每一层结束就翻转一下
vector<vector<int> >zigzagLevelOrder(TreeNode *root){
vector<vector<int> > result;
if(root==NULL) return result;
queue<TreeNode *>q;
bool left_to_right=true;
vector<int> level;
q.push(root); q.push(NULL); //层之间的间隔标记
while(!q.empty()){
TreeNode* cur=q.front();
q.pop();
if(cur){
level.push_back(cur-val);
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
}else{
if(left_to_right) result.push_back(level);
else{ reverse(level.begin(),level.end()); result.push_back(level); }
level.clear(); left_to_right=!left_to_right;
if(q.size()>0) q.push(NULL);
}
}
return result;
}
7->二叉搜索树,有两个结点的位置有错误,修正该二叉搜索树
解题方法:开辟一个指针数组,中序遍历,将指针依次存放在数组里,找出两个逆向的位置,交换它
void inOrderTraverse(TreeNode *root,TreeNode *&p1,TreeNode *&p2,TreeNode *&pre){
if(root==NULL) return ;
if(root->left!=NULL) inOrderTraverse(root->left,p1,p2,pre);
if(pre!=NULL && root->val<pre->val){
if(p1==NULL){p1=pre; p2=root;}
else p2=root;
}
pre=root;
if(root->right!=NULL) inOrderTraverse(root->right,p1,p2,pre);
}
void recoverTree(TreeNode *root){
TreeNode*p1=NULL,*p2=NULL,*pre=NULL;
inOrderTreaverse(root,p1,p2,pre);
swap(p1->val,p2->val;);
}
8->判断两个二叉树的结构是否相同
bool isSameTree(TreeNode *p,TreeNode *q){
if(p==NULL && q==NULL) return true;
if(p==NULL || q==NULL) return false;
return p->val==q->val && isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
非递归解法:
bool isSameTree(TreeNode *p,TreeNode *q){
stack<TreeNode *>s;
s.push(p); s.push(q);
while(!s.empty()){
p=s.top(); s.pop();
q=s.top(); s.pop();
if(p==NULL &&q==NULL) continue;
if(p==NULL || q==NULL) return false;
if(p->val !=q->val) return false;
s.push(p->left); s.push(q->left);
s.push(p->right); s.push(q->right);
}
return true;
}
9->判断一棵树是否对称
非递归版:
bool isSymmetric(TreeNode * root){
if(!root) return true;
stack<TreeNode *> s;
s.push(root->left); s.push(rot->right);
while(!s.empty()){
TreeNode *p=s.top(); s.pop();
TreeNode *q=s.top(); s.pop();
if(p==NULL && q==NULL) continue;
if(p==NULL || q==NULL) return false;
if(p->val!=q->val) return false;
s.push(p->left); s.push(q->right);
s.push(p->right); s.push(q->left);
}
return true;
}
递归版本:
bool isSymmetric(TreeNode *root){
return root?isSymmetric(root->left,root->right);
}
bool isSymmetric(TreeNode *left,TreeNode *right){
if(!left && !right) return true;
if(!left || !right) return false;
return left->val==right->val && isSymmetric(left->left,right->right) && isSymmetric(left->right,right->left);
}
10->判断一棵二叉树是否是平衡二叉树
解题方法:平衡二叉树的概念,左右子树的高度差绝对值不超过1,左右子树也是一棵平衡二叉树
bool isBalanced(TreeNode *root){
return balancedHeight(root)>=0;
}
int balancedHeight(TreeNode *root){ //求树的高度,如果是平衡二叉树返回当前高度,否则的话返回-1
if(root==NULL) return 0;
int left=balanceHeight(root->left);
int right=balanceHeight(root->right);
if(left<0 || right<0 || abs(left-right)>1) return -1; //不符合平衡二叉树的条件,剪枝
return max(left,right)+1;
}
11->将一个二叉树按照先序遍历转化成链表,要求原地转化
void flatten(TreeNode *root){
if(root==NULL) return;
flatten(root->left); flatten(root->right);
if(root->left==NULL) return;
TreeNode *p=root->left;
while(p->right) p=p->right;
p->right=root->right;
root->right=root->left;
root->left=NULL;
}
12->为任意叉树的每个节点添加一个指向其右兄弟的指针
解题方法:很自然的就想到用广度搜索的办法,但是广度搜索的空间复杂度非常数,而这一题要求的是原地转化
void connect(TreeLinkNode *root){
if(root==NULL) return ;
TreeLinkNode dummy(-1); //辅助头节点
for(TreeLinkNode *cur=root,*prev=&dummy;cur;cur=cur->next){
if(cur->left!=NULL){
prev->next=cur->left; prev=prev->next;
}
if(cur->right!=NULL){
prev->next=cur->right;prev=prev->next;
}
}
connect(dummy.next);
}
***************二叉树的建立*****************
1->根据二叉树的前序遍历和中序遍历构建二叉树
解题方法:递归的方法,前序遍历的第一个节点为根节点,中遍历根据根节点将树分为左右两边,递归建树,即可完成目标。
TreeNode * buildTree(vector<int>& preorder,vector<int>& inorder){
return buildTree(preorder.begin(),preorder.end(),inorder.begin(),inorder.end());
}
TreeNode *bulidTree(vector<int>::iterator pre_first,vector<int>::iterator pre_last,vector<int>::iterator in_first,vector<int>::iterator in_last){
if(pre_first==pre_last) return NULL;
if(in_first==in_last) return NULL;
TreeNode *root=new TreeNode(*pre_first);
vector<int>::iterator inRootPos=find(in_first,in_last,*pre_first);
int leftSize=distance(in_first,inRootPos);
root->left=buildTree(next(pre_first),next(pre_first,leftSize+1),in_first,next(in_first,leftSize));
root->right=buildTree(next(pre_first,leftSize+1),pre_last,next(inRootPos),in_last);
return root;
}
2->根据中序遍历和后序遍历建立二叉树
TreeNode * buildTree(vector<int>& inorder,vector<int>& postorder){
return buildTree(inorder.begin(),inorder.end(),postorder.begin(),postorder.end());
}
TreeNode* buildTree(vector<int>::iterator in_first,vector<int>::iterator in_last,vector<int>::iterator post_first,vector<int>::iterator post_last){
if(in_first==in_last) return NULL;
if(post_first==post_last) return NULL;
int val=*prev(post_last);
TreeNode* root=new TreeNode(val);
vector<int>::iterator in_root_pos=find(in_first,in_last,val);
int leftSize=distance(in_first,in_root_pos);
auto post_left_last=next(post_first,leftSize);
root->left=buildTree(in_first,int_root_pos,post_first,post_left_last);
root->right=buildTree(next(in_root_post),in_last,post_left_last,prev(post_last));
return root;
}
************二叉查找树***********
1->1到n个节点可以确定多少种不同的BST
解题方法:属于Catalan数的范畴。对于n个节点有递推公式:f(n)=f(0)*f(n-1)+f(1)*f(n-2)+.....+f(n-2)f(1)+f(n-1)*f(0),其中f(0)f(n-1)表示左子树0个节点,右子树n-1个节点的情况
int numTrees(int n){
vector<int> f(n+1,0);
f[0]=1;f[1]=1;
for(int i=2;i<=n;i++)
for(int k=1;k<=i;k++) f[i]+=f[k-1]*f[i-k];
return f[n];
}
2->和上一题不同,这一题要求,求出有n个节点的不同二叉搜索树
解题方法:一般采用递归的方法解决
vector <TreeNode *> generate(int start,int end){
vector<TreeNode *> subTree;
if(start>end){ subTree.push_back(NULL); return subTree; }
for(int k=start;k<=end;k++){
vector<TreeNode *> leftSubs=generate(start,k-1);
vector<TreeNode *> rightSubs=generate(k+1,end);
for(each i in leftSubs)
for(each j in rightSubs){
TreeNode *node=new TreeNode(k);
node->left=i; node ->right=j;
subTree.push_back(node);
}
}
return subTree;
}
3->判断一棵树是否是二叉搜索树
bool isValidBST(TreeNode* root){
return isValidBST(root,INT_MIN,INT_MAX);
}
bool isValidBST(TreeNode* root,int lower,int upper){
if(root==NULL) return true;
return root->val>lower &&root->val<upper && isValidBST(root->left,lower,root->val) &&isValidBST(root->right,root->val,upper);
}
4->将一个已经排序的数组转化为二叉搜索树
解题方法:采用二分法
TreeNode *sortedArrayToBST(int low,int high){
if(low>=high) return;
int mid=(low+high)/2;
TreeNode *root=new TreeNode(*mid);
root->left=sortedArrayToBST(low,mid);
root->right=sortedArrayToBST(mid+1,high);
return root;
}
5->将一个已经排序的链表转化为二叉搜索树
解题方法:采用二分法,只是链表不支持随机存储。要自己实现中间位置的查找
*************二叉树的递归*******************
1->树的最小深度
递归版本:
int minDepth(const TreeNode *root){
return minDepth(root,false);
}
int minDepth(const TreeNode *root,bool hasbrother){
if(!root) return hasbrother?INT_MAX:0;
return 1+min(minDepth(root->left,root->right!=NULL),minDepth(root->right,root->left!=NULL));
}
迭代版本:
int minDepth(TreeNode *root){
if(root==NULL) return 0;
int result=INT_MAX;
stack<pair<TreeNode *,int> >s;
s.push(make_pair(root,1));
while(!s.empty()){
TreeNode * node=s.top()->first;
int depth=s.top()->second; s.pop();
if(node->left==NULL && node->right==NULL) result=min(result,depth);
if(node->left && result>depth) s.push_back(make_pair(node->left,depth+1));
if(node->right && result>depth) s.push_back(make_pair(node->right,depth+1));
}
return result;
}
2->二叉树的最大深度
递归的方法:
int maxDepth(TreeNode *root){
if(root==NULL) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
3->判断二叉树的根到节点是否存在和为某一值的路径,要求返回true或者false。
解题方法:采用朴素的深度搜索方法
bool hasPathSum(TreeNode* root,int sum){
if(root==NULL) return false;
if(root->left==NULL && root->right==NULL) //到达叶子结点
return sum==root->val;
return hasPathSum(root->left,sum-root->val) || hasPathSum(root->left,sum-root->val);
}
4->题目要求与上一题相同,不同点是要求求出所有可能的结果。
解题方法:DFS方法
vector <vector<int> > pathSum(TreeNode *root,int sum){
vector< vector<int> >result;
vector<int> cur;
pathSum(root,sum,cur,result);
return result;
}
void pathSum(TreeNode* root,int gap,vector<int>&cur,vector<vector<int> >&result){
if(root==NULL) return;
cur.push_back(root->val);
if(root->left==NULL && root->right==NULL) { if(grap==root->val) result.push_back(cur);}
pathSum(root->left,grap-root->val,cur,result);
pathSum(root->right,grap-root->val,cur,result);
cur.pop_back();
}
5->找出二叉树中和最大的路径,起点可以为任何结点,终点也可以试任何结点
int maxPathSum(TreeNode *root){
max_sum=INT_MIN; helper(root); return max_sum; //其中max_sum为全局变量
}
int helper(TreeNode *root){
if(root==NULL) return 0;
int l=helper(root->left);
int r=helper(root->right);
int sum=root->val;
if(l>0) sum+=l; if(r>0) sum+=r;
max_sum=max(max_sum,sum);
return max(r,l)>0 ?max(l,r)+root->val:root->val;
}
6->将二叉树总的每层结点链接起来(在二叉树的遍历中有一题类似的,不过是在多叉树上进行这一个操作)
void connect(TreeLinkNode *root){
connect(root,NULL);
}
void connect(TreeLinkNode *root,TreeLinkNode* sibling){
if(root==NULL) return ;
else root->next=sibling;
connect(root->left,root->right);
if(sibling!=NULL)
connect(root->right,sibling->left);
else
connect(root->right,NULL);
}
7->sum Root to leaf Numbers(一个二叉树的结点值为0到9的数值,将root到叶子结点的路径上的结点值,组合成一个数值,求出这些数值的和)
int sumNumbers(TreeNode *root){
return helper(root,0);
}
int helper(TreeNode *root,int sum){
if(root==NULL) return 0;
if(root->left==NULL && root->right==NULL) return sum*10+root->val;
return helper(root->left,sum*10+root->val)+helper(root->right,sum*10+root->val);
}