树
2016-07-05 17:57
134 查看
1.二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if(pRoot == NULL)
return 0; // 递归结束条件
int ld = 0,rd = 0;
ld = TreeDepth(pRoot->left);
rd = TreeDepth(pRoot->right);
return ld > rd ? ld+1 : rd+1; // 返回上一层了,说明这一层有东西,深度+1
}
};
2.平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。代码如下:
class Solution {
public:
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot==NULL)
return true;
int left=Depth(pRoot->left);
int right=Depth(pRoot->right);
int diff=left-right;
if(diff>1||diff<-1)
return false;
return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
}
int Depth(TreeNode* root)
{
if(root==0)
return 0;
int left=Depth(root->left);
int right=Depth(root->right);
return left>right?left+1:right+1;
}
};
3.二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
using namespace std;
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL){
return NULL;
}
if(pNode->right!=NULL){
pNode=pNode->right;
while(pNode->left!=NULL){
pNode=pNode->left;
}
return pNode;
}
while(pNode->next!=NULL){
TreeLinkNode* proot=pNode->next;
if(proot->left==pNode)
return proot;
pNode=pNode->next;
}
return NULL;
}
};
4.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if(pRoot==NULL){
return true;
}
return issame(pRoot->left,pRoot->right);
}
bool issame(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot1==NULL&&pRoot2!=NULL){return false;}
if(pRoot2==NULL&&pRoot1!=NULL){return false;}
if(pRoot1==NULL&&pRoot2==NULL){return true;}
if(pRoot1->val==pRoot2->val){
return issame(pRoot1->left,pRoot2->right)&&issame(pRoot2->left,pRoot1->right);
}
else return false;
}
};
5.按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
stack<TreeNode *> stack1,stack2;
bool direction = true;//向右打印为true,向左打印为false
if(pRoot!=NULL)
stack1.push(pRoot);
struct TreeNode *node;
while(!stack1.empty() || !stack2.empty()){
vector<int> data;
if(!stack1.empty()){
while(!stack1.empty()){
node = stack1.top();
stack1.pop();
data.push_back(node->val);
if(node->left!=NULL)
stack2.push(node->left);
if(node->right!=NULL)
stack2.push(node->right);
}
result.push_back(data);
}
else if(!stack2.empty()){
while(!stack2.empty()){
node = stack2.top();
stack2.pop();
data.push_back(node->val);
if(node->right!=NULL)
stack1.push(node->right);
if(node->left!=NULL)
stack1.push(node->left);
}
result.push_back(data);
}
}
return result;
}
};
6.把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > vec;
if(pRoot == NULL) return vec;
queue<TreeNode*> q;
q.push(pRoot);
while(!q.empty())
{
int lo = 0, hi = q.size();
vector<int> c;
while(lo++ < hi)
{
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
vec.push_back(c);
}
return vec;
}
};
7.二叉搜索树的第k个结点
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<TreeNode*> res;
TreeNode* KthNode(TreeNode* pRoot, unsigned int k)
{
if(pRoot==NULL||k==0)
return NULL;
inorder(pRoot);
if(k>res.size())
return NULL;
else
return res[k-1];
}
void inorder(TreeNode* pRoot){
if(pRoot==NULL)
return;
inorder(pRoot->left);
res.push_back(pRoot);
inorder(pRoot->right);
}
};
8.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/* 先序遍历第一个位置肯定是根节点node,
中序遍历的根节点位置在中间p,在p左边的肯定是node的左子树的中序数组,p右边的肯定是node的右子树的中序数组
另一方面,先序遍历的第二个位置到p,也是node左子树的先序子数组,剩下p右边的就是node的右子树的先序子数组
把四个数组找出来,分左右递归调用即可
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
int in_size = in.size();
if(in_size==0){
return NULL;
}
vector<int> pre_left, pre_right, in_left, in_right;
int val = pre[0];
TreeNode* node = new TreeNode(val);
int p = 0;
for(p; p < in_size; ++p){
if(in[p] == val) //Find the root position in in
break;
}
for(int i = 0; i < in_size; ++i){
if(i < p){
in_left.push_back(in[i]);
pre_left.push_back(pre[i+1]);
}
else if(i > p){
in_right.push_back(in[i]);
pre_right.push_back(pre[i]);
}
}
node->left = reConstructBinaryTree(pre_left, in_left);
node->right = reConstructBinaryTree(pre_right, in_right);
return node;
}
};
9.树的子结构
输入两颗二叉树A,B,判断B是不是A的子结构。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
bool result=false;
if(pRoot1!=NULL&&pRoot2!=NULL){
if(pRoot1->val==pRoot2->val)
result=DoseTree1HaveTree2(pRoot1,pRoot2);
if(!result)
result=HasSubtree(pRoot1->left,pRoot2);
if(!result)
result=HasSubtree(pRoot1->right,pRoot2);
}
return result;
}
bool DoseTree1HaveTree2(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot2==NULL)
return true;
if(pRoot1==NULL)
return false;
if(pRoot1->val!=pRoot2->val)
return false;
return DoseTree1HaveTree2(pRoot1->left,pRoot2->left)&&DoseTree1HaveTree2(pRoot1->right,pRoot2->right);
}
};
10.二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot==NULL)
return;
if(pRoot->left==NULL&&pRoot->right==NULL)
return;
TreeNode *pTemp=pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=pTemp;
if(pRoot->left)
Mirror(pRoot->left);
if(pRoot->right)
Mirror(pRoot->right);
}
};
11.二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
class Solution {
public:
bool VerifySquenceOfBST(int sequence[],int length) {
if (sequence==NULL||length<=0)
return false;
int root=sequence[length-1];
int i=0;
for(;i<length-1;++i)
{
if(sequence[i]>root)
break;
}
int j=i;
for(;j<length-1;++j)
{
if(sequence[j]<root)
break;
}
bool left=true;
if(i>0)
left=VerifySquenceOfBST(sequence,i);
bool right=true;
if(i<length-1)
right=VerifySquenceOfBST(sequence+i,length-i-1);
return (left&&right);
}
};
12.二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/*
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)
{
TreeNode* pLastNodeInList=NULL;
ConvertNode(pRootOfTree,&pLastNodeInList);
TreeNode* pHeadOfList=pLastNodeInList;
while(pHeadOfList!=NULL&&pHeadOfList->left!=NULL){
pHeadOfList=pHeadOfList->left;
}
return pHeadOfList;
}
void ConvertNode(TreeNode* pNode,TreeNode** pLastNodeInList){
if(pNode==NULL){
return;
}
TreeNode* pCurrent=pNode;
if(pCurrent->left!=NULL){
ConvertNode(pCurrent->left,pLastNodeInList);
}
pCurrent->left=*pLastNodeInList;
if(*pLastNodeInList!=NULL){
(*pLastNodeInList)->right=pCurrent;
}
*pLastNodeInList=pCurrent;
if(pCurrent->right!=NULL){
ConvertNode(pCurrent->right,pLastNodeInList);
}
}
};
13.输出单层结点
对于一棵二叉树,请设计一个算法,创建含有某一深度上所有结点的链表。给定二叉树的根结点指针TreeNode*root,以及链表上结点的深度,请返回一个链表ListNode,代表该深度上所有结点的值,请按树上从左往右的顺序链接,保证深度不超过树的高度,树上结点的值为非负整数且不超过100000。
<方法1>:层次遍历
这个题目的意思就是输出二叉树的某一层的所有元素,这个首先想到的是层次遍历,层次遍历最简单的方法就是用队列实现,我们传统的层次遍历方法是可以输出所有元素,那么如何区分相邻两层之间的元素呢?
其实我们可以用两个整数变量line1,line2来记录相邻两层的元素个数,其中line1代表出栈那一层留下的元素个数,line2代表下一层进栈元素的个数,每当line1为0的时候,说明上一层已经全部出栈,下一层已经全部入栈,那么层次遍历层数就加一,这个时候将line2的值复制给line1,line2=0,当遍历到第dep层的时候,便把那一层的所有元素输出,停止遍历。
代码实现如下:
class TreeLevel {
public:
ListNode* getTreeLevel(TreeNode* root, int dep) {
// write code here
if(dep<=0||root==NULL)
return NULL;
ListNode* list=new ListNode(-1);
ListNode* listHead=list;
queue<TreeNode*> qu;
qu.push(root);
int lines1=1,lines2=0,num=1;
while(!qu.empty())
{
if(num==dep)
{
for(int i=0;i<lines1;i++)
{
TreeNode* root1=qu.front();
list->next=new ListNode(root1->val);
list=list->next;
qu.pop();
}
return listHead->next;
}
TreeNode* root1=qu.front();
if(root1->left)
{
qu.push(root1->left);
lines2++;
}
if(root1->right)
{
qu.push(root1->right);
lines2++;
}
qu.pop();
if(--lines1==0)
{
lines1=lines2;
lines2=0;
num++;
}
}
return listHead->next;
}
};
<方法2>:递归遍历
其实也可以用递归遍历实现,刚开始为深度为dep,每往下递归一层,则深度减一(dep=dep-1),当dep==1的时候,便输出那个元素,如果先递归左子树,那么则实现从左到右打印,如果先递归右子树,则实现从右往左打印。
程序代码如下:
class TreeLevel {
public:
ListNode* getTreeLevel(TreeNode* root, int dep) {
// write code here
ListNode* list=new ListNode(-1);
ListNode* listHead=list;
get1(root,list,dep);
return listHead->next;
}
void get1(TreeNode* root,ListNode* &list,int dep)
{
if(dep<=0||root==NULL)
return;
if(dep==1)
{
ListNode* listnext=new ListNode(root->val);
list->next=listnext;
list=list->next;
return ;
}
get1(root->left,list,dep-1);
get1(root->right,list,dep-1);
}
};
14.检查是否为BST
请实现一个函数,检查一棵二叉树是否为二叉查找树。
给定树的根结点指针TreeNode* root,请返回一个bool,代表该树是否为二叉查找树。
<方法1>
首先我们想到的是二叉树中序遍历后的结果是有序的,根据这个结果,我们可以中序遍历二叉树,并把遍历结果存放在一个数组里面,然后判断这个数组大小是否是有序数组,如果是有序数组,则是二叉查找树,否则就不是。
这个方法的时间复杂度是O(N),但是空间复杂度比较高,需要浪费O(N)的存储空间。
<方法2>
其实在<方法1>的基础上,我们可以在中序遍历的同时,比较大小,每次记录下上次遍历过的元素的值,如果当前元素的值大于上次遍历元素的值,则接着遍历,否则返回false,因为这个记录是一个址传递,所以需要用到引用形参进行传递。
这个方法的时间复杂度与<方法1>的时间复杂度相同,只是空间复杂度只需要一个元素O(1)。
代码实现如下:
class Checker {
public:
bool checkBST(TreeNode* root) {
// write code here
int min=INT_MIN;
return method1(root,min);
}
bool method1(TreeNode* root,int &last)
{
if(root==NULL)
return true;
if(!method1(root->left,last))
return false;
if(root->val<last)
return false;
last=root->val;
if(!method1(root->right,last))
return false;
return true;
}
};
<方法3>
可以根据二叉查找树的定义来判断,二叉树的定义,所有左子树的节点小于根节点,所有右子树的节点大于根节点,并且左右子树也是二叉查找树。所以在递归的过程中,我们只需要传递两个参数(当前根节点对应的二叉树的所有节点的最大值和最小值),同时不断的更新这两个参数,如果当前节点的值不在这两个数范围中,则直接返回false,否则接着递归便可。
代码实现如下:
class Checker {
public:
bool checkBST(TreeNode* root) {
// write code here
return method2(root,INT_MIN,INT_MAX);
}
bool method2(TreeNode* root,int min,int max)
{
if(root==NULL)
return true;
if(root->val<min||root->val>max)
return false;
return method2(root->left,min,root->val)&&method2(root->right,root->val,max);
}
};
15.寻找下一个结点
请设计一个算法,寻找二叉树中指定结点的下一个结点(即中序遍历的后继)。
给定树的根结点指针TreeNode* root和结点的值int p,请返回值为p的结点的后继结点的值。保证结点的值大于等于零小于等于100000且没有重复值,若不存在后继返回-1。
要寻找中序遍历的某个节点的下一个节点,肯定是要通过中序遍历实现的,题目中明确告诉我们节点的值没有重复,所以只要在中序遍历的过程中,某个节点的值等于p,则告诉递归者下一个要遍历的节点便是我们要找的节点,这个需要有个信号在多次递归之间进行传递消息,c++里用引用完全可以实现,只需要传递一个bool类型的引用便可。
程序实现代码:
class Successor {
public:
int findSucc(TreeNode* root, int p) {
// write code here
bool sign=0;
return findSucc1(root,p,sign);
}
int findSucc1(TreeNode* root,int p,bool &sign)
{
if(root==NULL)
return -1;
int left=findSucc1(root->left,p,sign);
if(left!=-1)
return left;
if(sign==true)
return root->val;
if(root->val==p)
sign=true;
return findSucc1(root->right,p,sign);
}
};
16.二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber)
{
vector<vector<int> >result;
vector<int> path;
int currentNumber=0;
if(root==NULL)return result;
subFindPath(root,expectNumber,currentNumber,path,result);
return result;
}
void subFindPath(TreeNode* root,int expectNumber,int¤tNumber,vector<int>& path,vector<vector<int> >& result)
{
currentNumber+=root->val;
path.push_back(root->val);
bool isleaf=(root->left==NULL)&&(root->right==NULL);
if((currentNumber==expectNumber)&&isleaf)
result.push_back(path);
if(root->left!=NULL)
subFindPath(root->left,expectNumber,currentNumber,path,result);
if(root->right!=NULL)
subFindPath(root->right,expectNumber,currentNumber,path,result);
path.pop_back();
currentNumber-=root->val;
}
};
17.最近公共祖先
有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为1。现在有两个结点a,b。请设计一个算法,求出a和b点的最近公共祖先的编号。
给定两个int a,b。为给定结点的编号。请返回a和b的最近公共祖先的编号。注意这里结点本身也可认为是其祖先。
测试样例:
2,3
返回:1
class LCA {
public:
int getLCA(int a, int b) {
// write code here
//方式一:(不使用额外的存储空间)
while(a!=b){
if(a>b){
a >>= 1;
}else{
b >>= 1;
}
}
return a;
}
};
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if(pRoot == NULL)
return 0; // 递归结束条件
int ld = 0,rd = 0;
ld = TreeDepth(pRoot->left);
rd = TreeDepth(pRoot->right);
return ld > rd ? ld+1 : rd+1; // 返回上一层了,说明这一层有东西,深度+1
}
};
2.平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。代码如下:
class Solution {
public:
bool IsBalanced_Solution(TreeNode* pRoot) {
if(pRoot==NULL)
return true;
int left=Depth(pRoot->left);
int right=Depth(pRoot->right);
int diff=left-right;
if(diff>1||diff<-1)
return false;
return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
}
int Depth(TreeNode* root)
{
if(root==0)
return 0;
int left=Depth(root->left);
int right=Depth(root->right);
return left>right?left+1:right+1;
}
};
3.二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
using namespace std;
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL){
return NULL;
}
if(pNode->right!=NULL){
pNode=pNode->right;
while(pNode->left!=NULL){
pNode=pNode->left;
}
return pNode;
}
while(pNode->next!=NULL){
TreeLinkNode* proot=pNode->next;
if(proot->left==pNode)
return proot;
pNode=pNode->next;
}
return NULL;
}
};
4.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if(pRoot==NULL){
return true;
}
return issame(pRoot->left,pRoot->right);
}
bool issame(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot1==NULL&&pRoot2!=NULL){return false;}
if(pRoot2==NULL&&pRoot1!=NULL){return false;}
if(pRoot1==NULL&&pRoot2==NULL){return true;}
if(pRoot1->val==pRoot2->val){
return issame(pRoot1->left,pRoot2->right)&&issame(pRoot2->left,pRoot1->right);
}
else return false;
}
};
5.按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > result;
stack<TreeNode *> stack1,stack2;
bool direction = true;//向右打印为true,向左打印为false
if(pRoot!=NULL)
stack1.push(pRoot);
struct TreeNode *node;
while(!stack1.empty() || !stack2.empty()){
vector<int> data;
if(!stack1.empty()){
while(!stack1.empty()){
node = stack1.top();
stack1.pop();
data.push_back(node->val);
if(node->left!=NULL)
stack2.push(node->left);
if(node->right!=NULL)
stack2.push(node->right);
}
result.push_back(data);
}
else if(!stack2.empty()){
while(!stack2.empty()){
node = stack2.top();
stack2.pop();
data.push_back(node->val);
if(node->right!=NULL)
stack1.push(node->right);
if(node->left!=NULL)
stack1.push(node->left);
}
result.push_back(data);
}
}
return result;
}
};
6.把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > vec;
if(pRoot == NULL) return vec;
queue<TreeNode*> q;
q.push(pRoot);
while(!q.empty())
{
int lo = 0, hi = q.size();
vector<int> c;
while(lo++ < hi)
{
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
vec.push_back(c);
}
return vec;
}
};
7.二叉搜索树的第k个结点
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<TreeNode*> res;
TreeNode* KthNode(TreeNode* pRoot, unsigned int k)
{
if(pRoot==NULL||k==0)
return NULL;
inorder(pRoot);
if(k>res.size())
return NULL;
else
return res[k-1];
}
void inorder(TreeNode* pRoot){
if(pRoot==NULL)
return;
inorder(pRoot->left);
res.push_back(pRoot);
inorder(pRoot->right);
}
};
8.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/* 先序遍历第一个位置肯定是根节点node,
中序遍历的根节点位置在中间p,在p左边的肯定是node的左子树的中序数组,p右边的肯定是node的右子树的中序数组
另一方面,先序遍历的第二个位置到p,也是node左子树的先序子数组,剩下p右边的就是node的右子树的先序子数组
把四个数组找出来,分左右递归调用即可
*/
class Solution {
public:
struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {
int in_size = in.size();
if(in_size==0){
return NULL;
}
vector<int> pre_left, pre_right, in_left, in_right;
int val = pre[0];
TreeNode* node = new TreeNode(val);
int p = 0;
for(p; p < in_size; ++p){
if(in[p] == val) //Find the root position in in
break;
}
for(int i = 0; i < in_size; ++i){
if(i < p){
in_left.push_back(in[i]);
pre_left.push_back(pre[i+1]);
}
else if(i > p){
in_right.push_back(in[i]);
pre_right.push_back(pre[i]);
}
}
node->left = reConstructBinaryTree(pre_left, in_left);
node->right = reConstructBinaryTree(pre_right, in_right);
return node;
}
};
9.树的子结构
输入两颗二叉树A,B,判断B是不是A的子结构。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
bool result=false;
if(pRoot1!=NULL&&pRoot2!=NULL){
if(pRoot1->val==pRoot2->val)
result=DoseTree1HaveTree2(pRoot1,pRoot2);
if(!result)
result=HasSubtree(pRoot1->left,pRoot2);
if(!result)
result=HasSubtree(pRoot1->right,pRoot2);
}
return result;
}
bool DoseTree1HaveTree2(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot2==NULL)
return true;
if(pRoot1==NULL)
return false;
if(pRoot1->val!=pRoot2->val)
return false;
return DoseTree1HaveTree2(pRoot1->left,pRoot2->left)&&DoseTree1HaveTree2(pRoot1->right,pRoot2->right);
}
};
10.二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if(pRoot==NULL)
return;
if(pRoot->left==NULL&&pRoot->right==NULL)
return;
TreeNode *pTemp=pRoot->left;
pRoot->left=pRoot->right;
pRoot->right=pTemp;
if(pRoot->left)
Mirror(pRoot->left);
if(pRoot->right)
Mirror(pRoot->right);
}
};
11.二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
class Solution {
public:
bool VerifySquenceOfBST(int sequence[],int length) {
if (sequence==NULL||length<=0)
return false;
int root=sequence[length-1];
int i=0;
for(;i<length-1;++i)
{
if(sequence[i]>root)
break;
}
int j=i;
for(;j<length-1;++j)
{
if(sequence[j]<root)
break;
}
bool left=true;
if(i>0)
left=VerifySquenceOfBST(sequence,i);
bool right=true;
if(i<length-1)
right=VerifySquenceOfBST(sequence+i,length-i-1);
return (left&&right);
}
};
12.二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/*
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)
{
TreeNode* pLastNodeInList=NULL;
ConvertNode(pRootOfTree,&pLastNodeInList);
TreeNode* pHeadOfList=pLastNodeInList;
while(pHeadOfList!=NULL&&pHeadOfList->left!=NULL){
pHeadOfList=pHeadOfList->left;
}
return pHeadOfList;
}
void ConvertNode(TreeNode* pNode,TreeNode** pLastNodeInList){
if(pNode==NULL){
return;
}
TreeNode* pCurrent=pNode;
if(pCurrent->left!=NULL){
ConvertNode(pCurrent->left,pLastNodeInList);
}
pCurrent->left=*pLastNodeInList;
if(*pLastNodeInList!=NULL){
(*pLastNodeInList)->right=pCurrent;
}
*pLastNodeInList=pCurrent;
if(pCurrent->right!=NULL){
ConvertNode(pCurrent->right,pLastNodeInList);
}
}
};
13.输出单层结点
对于一棵二叉树,请设计一个算法,创建含有某一深度上所有结点的链表。给定二叉树的根结点指针TreeNode*root,以及链表上结点的深度,请返回一个链表ListNode,代表该深度上所有结点的值,请按树上从左往右的顺序链接,保证深度不超过树的高度,树上结点的值为非负整数且不超过100000。
<方法1>:层次遍历
这个题目的意思就是输出二叉树的某一层的所有元素,这个首先想到的是层次遍历,层次遍历最简单的方法就是用队列实现,我们传统的层次遍历方法是可以输出所有元素,那么如何区分相邻两层之间的元素呢?
其实我们可以用两个整数变量line1,line2来记录相邻两层的元素个数,其中line1代表出栈那一层留下的元素个数,line2代表下一层进栈元素的个数,每当line1为0的时候,说明上一层已经全部出栈,下一层已经全部入栈,那么层次遍历层数就加一,这个时候将line2的值复制给line1,line2=0,当遍历到第dep层的时候,便把那一层的所有元素输出,停止遍历。
代码实现如下:
class TreeLevel {
public:
ListNode* getTreeLevel(TreeNode* root, int dep) {
// write code here
if(dep<=0||root==NULL)
return NULL;
ListNode* list=new ListNode(-1);
ListNode* listHead=list;
queue<TreeNode*> qu;
qu.push(root);
int lines1=1,lines2=0,num=1;
while(!qu.empty())
{
if(num==dep)
{
for(int i=0;i<lines1;i++)
{
TreeNode* root1=qu.front();
list->next=new ListNode(root1->val);
list=list->next;
qu.pop();
}
return listHead->next;
}
TreeNode* root1=qu.front();
if(root1->left)
{
qu.push(root1->left);
lines2++;
}
if(root1->right)
{
qu.push(root1->right);
lines2++;
}
qu.pop();
if(--lines1==0)
{
lines1=lines2;
lines2=0;
num++;
}
}
return listHead->next;
}
};
<方法2>:递归遍历
其实也可以用递归遍历实现,刚开始为深度为dep,每往下递归一层,则深度减一(dep=dep-1),当dep==1的时候,便输出那个元素,如果先递归左子树,那么则实现从左到右打印,如果先递归右子树,则实现从右往左打印。
程序代码如下:
class TreeLevel {
public:
ListNode* getTreeLevel(TreeNode* root, int dep) {
// write code here
ListNode* list=new ListNode(-1);
ListNode* listHead=list;
get1(root,list,dep);
return listHead->next;
}
void get1(TreeNode* root,ListNode* &list,int dep)
{
if(dep<=0||root==NULL)
return;
if(dep==1)
{
ListNode* listnext=new ListNode(root->val);
list->next=listnext;
list=list->next;
return ;
}
get1(root->left,list,dep-1);
get1(root->right,list,dep-1);
}
};
14.检查是否为BST
请实现一个函数,检查一棵二叉树是否为二叉查找树。
给定树的根结点指针TreeNode* root,请返回一个bool,代表该树是否为二叉查找树。
<方法1>
首先我们想到的是二叉树中序遍历后的结果是有序的,根据这个结果,我们可以中序遍历二叉树,并把遍历结果存放在一个数组里面,然后判断这个数组大小是否是有序数组,如果是有序数组,则是二叉查找树,否则就不是。
这个方法的时间复杂度是O(N),但是空间复杂度比较高,需要浪费O(N)的存储空间。
<方法2>
其实在<方法1>的基础上,我们可以在中序遍历的同时,比较大小,每次记录下上次遍历过的元素的值,如果当前元素的值大于上次遍历元素的值,则接着遍历,否则返回false,因为这个记录是一个址传递,所以需要用到引用形参进行传递。
这个方法的时间复杂度与<方法1>的时间复杂度相同,只是空间复杂度只需要一个元素O(1)。
代码实现如下:
class Checker {
public:
bool checkBST(TreeNode* root) {
// write code here
int min=INT_MIN;
return method1(root,min);
}
bool method1(TreeNode* root,int &last)
{
if(root==NULL)
return true;
if(!method1(root->left,last))
return false;
if(root->val<last)
return false;
last=root->val;
if(!method1(root->right,last))
return false;
return true;
}
};
<方法3>
可以根据二叉查找树的定义来判断,二叉树的定义,所有左子树的节点小于根节点,所有右子树的节点大于根节点,并且左右子树也是二叉查找树。所以在递归的过程中,我们只需要传递两个参数(当前根节点对应的二叉树的所有节点的最大值和最小值),同时不断的更新这两个参数,如果当前节点的值不在这两个数范围中,则直接返回false,否则接着递归便可。
代码实现如下:
class Checker {
public:
bool checkBST(TreeNode* root) {
// write code here
return method2(root,INT_MIN,INT_MAX);
}
bool method2(TreeNode* root,int min,int max)
{
if(root==NULL)
return true;
if(root->val<min||root->val>max)
return false;
return method2(root->left,min,root->val)&&method2(root->right,root->val,max);
}
};
15.寻找下一个结点
请设计一个算法,寻找二叉树中指定结点的下一个结点(即中序遍历的后继)。
给定树的根结点指针TreeNode* root和结点的值int p,请返回值为p的结点的后继结点的值。保证结点的值大于等于零小于等于100000且没有重复值,若不存在后继返回-1。
要寻找中序遍历的某个节点的下一个节点,肯定是要通过中序遍历实现的,题目中明确告诉我们节点的值没有重复,所以只要在中序遍历的过程中,某个节点的值等于p,则告诉递归者下一个要遍历的节点便是我们要找的节点,这个需要有个信号在多次递归之间进行传递消息,c++里用引用完全可以实现,只需要传递一个bool类型的引用便可。
程序实现代码:
class Successor {
public:
int findSucc(TreeNode* root, int p) {
// write code here
bool sign=0;
return findSucc1(root,p,sign);
}
int findSucc1(TreeNode* root,int p,bool &sign)
{
if(root==NULL)
return -1;
int left=findSucc1(root->left,p,sign);
if(left!=-1)
return left;
if(sign==true)
return root->val;
if(root->val==p)
sign=true;
return findSucc1(root->right,p,sign);
}
};
16.二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber)
{
vector<vector<int> >result;
vector<int> path;
int currentNumber=0;
if(root==NULL)return result;
subFindPath(root,expectNumber,currentNumber,path,result);
return result;
}
void subFindPath(TreeNode* root,int expectNumber,int¤tNumber,vector<int>& path,vector<vector<int> >& result)
{
currentNumber+=root->val;
path.push_back(root->val);
bool isleaf=(root->left==NULL)&&(root->right==NULL);
if((currentNumber==expectNumber)&&isleaf)
result.push_back(path);
if(root->left!=NULL)
subFindPath(root->left,expectNumber,currentNumber,path,result);
if(root->right!=NULL)
subFindPath(root->right,expectNumber,currentNumber,path,result);
path.pop_back();
currentNumber-=root->val;
}
};
17.最近公共祖先
有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为1。现在有两个结点a,b。请设计一个算法,求出a和b点的最近公共祖先的编号。
给定两个int a,b。为给定结点的编号。请返回a和b的最近公共祖先的编号。注意这里结点本身也可认为是其祖先。
测试样例:
2,3
返回:1
class LCA {
public:
int getLCA(int a, int b) {
// write code here
//方式一:(不使用额外的存储空间)
while(a!=b){
if(a>b){
a >>= 1;
}else{
b >>= 1;
}
}
return a;
}
};
相关文章推荐
- mysql sql语句大全
- vim简单使用教程
- JAVA发送http get/post请求,调用http接口、方法
- 超有用的分页
- Matlab 括号用法
- 在两台服务器之间建立信任关系解决scp,ssh等不用输入密码等问题
- 未能正确加载“Microsoft.VisualStudio.Editor.Implementation.EditorPackage”包。
- Ubuntu下ROS的安装与测试
- "Service"-安卓面试必问技能点大总结"
- 内存和缓存的区别
- IntelliJ Idea 常用快捷键列表
- 软件版本阶段命名
- Image Perimeters
- 常见表连接方式
- 强制横屏
- adb shell error: no devices/emulators found
- Ubuntu下的LAMP环境搭建笔记 (基础向)
- C语言的数组
- iOS相机 相册 麦克风 定位等权限是否拥有
- 没有歌词的女流氓 王若虚