五.树
5.1二叉树的遍历 分别写出递归和迭代版本*
5.1.1.先序优先遍历 Binary Tree Preorder Traversal
递归版本
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
vector<int > ret;
helper(ret,root);
return ret;
}
void helper(vector<int>&ret , TreeNode* root){
if(root==NULL)return ;
else
ret.push_back(root->val);
if(root->left!=NULL)
helper(ret,root->left);
if(root->right!=NULL)
helper(ret,root->right);
}
};
迭代版本
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
//用栈来实现先序优先遍历
vector<int > ret;
if(root==NULL) return ret;
stack<TreeNode* > mystack;
mystack.push(root);
TreeNode* temp;
while(!mystack.empty()){
temp= mystack.top();
mystack.pop();
ret.push_back(temp->val); //先把右子节点入栈
if(temp->right!=NULL)
mystack.push(temp->right);
if(temp->left!= NULL)
mystack.push(temp->left);
}
return ret;
}
};
5.1.2中序优先遍历
递归版本
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
vector<int > ret;
helper(ret, root);
return ret;
}
void helper(vector<int>&ret ,TreeNode* root){
if(root==NULL) return;
if(root->left!=NULL)
helper(ret,root->left);
ret.push_back(root->val);
if(root->right!=NULL)
helper(ret,root->right);
}
};
迭代版本
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
if(root==NULL) return ret;
stack<TreeNode* > mystack;
TreeNode* p=root;
while(p!=NULL){
mystack.push(p);
p=p->left;
}
while(!mystack.empty()){
TreeNode * temp = mystack.top();
mystack.pop();
ret.push_back(temp->val);
if(temp->right!=NULL){ //如果出栈的节点右子节点不空,这将右子节点的左子节点入入栈,直到没有左子节点
p=temp->right;
while(p!=NULL){
mystack.push(p);
p=p->left;
}
}
}
return ret;
}
};
5.1.3 后序优先遍历
思考:
步骤:
-
- 1.
-
-
-
- 3.
-
- 注意:
5.1.4 输出二叉树的每层的数。 leetcode 102
思考:
递归版本,相当于广度优先遍历,用一个参数来表明大小步骤:
-
- 1.
-
-
-
- 3.
-
- 注意:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int> > ret;
if(root==NULL)
return ret;
helper(root, ret,0);
return ret;
}
void helper(TreeNode* root, vector<vector<int> > &ret,int level){
if(!root)return ;
if(level+1>ret.size() ) //注意 level>ret.size()-1 unsigned int 与 int 运算时, int 会被转换为unit
ret.push_back(vector<int>());
ret[level].push_back(root->val);
if(root->left!=NULL)
helper(root->left, ret ,level+1);
if(root->right!=NULL)
helper(root->right, ret,level+1);
}
};
class Solution {
public:
vector<vector<int> > levelOrder(TreeNode* root) {
vector<vector<int> > ret;
if(root==NULL)
return ret;
vector<TreeNode* > layer;
layer.push_back(root);
while(!layer.empty()){
vector<int> temp;
vector<TreeNode* > deq;
TreeNode* t;
for(int i=0 ;i<layer.size();i++){
t= layer[i];
temp.push_back(t->val);
if(t->left)
deq.push_back(t->left);
if(t->right)
deq.push_back(t->right);
}
ret.push_back(temp);
layer=deq;
}
return ret;
}
};
class Solution {
public:
vector<vector<int> > levelOrder(TreeNode* root) {
vector<vector<int> > ret;
if(root==NULL)
return ret;
deque<TreeNode* > deq1;
deque<TreeNode* > deq2;
deq1.push_back(root);
while(!deq1.empty())
{
vector<int> temp;
TreeNode* t;
while(!deq1.empty()){
t=deq1.front();
deq1.pop_front();
temp.push_back(t->val);
if(t->left)
deq2.push_back(t->left);
if(t->right)
deq2.push_back(t->right);
}
ret.push_back(temp);
swap(deq1,deq2); //这个知识交换指向的空间,并没有复制操作
}
return ret;
}
};
5.1.5 返回二叉树每层最右边的节点
结果同上:
//只不过是
//result[i]=root->val; 不断根新最后一个数存放的数组
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> ret;
vector<TreeNode* > layer;
if(root==NULL) return ret;
layer.push_back(root);
int level=0;
while(!layer.empty()){
vector<TreeNode* > temp;
for(int i=0;i<layer.size();i++){
TreeNode* p=layer[i];
if(level+1>ret.size())
ret.resize(level+1);
ret[level]=layer[i]->val;
if(p->left!=NULL)
temp.push_back(p->left);
if(p->right!=NULL)
temp.push_back(p->right);
}
layer=temp;
level++;
}
return ret;
}
};
5.2树的判定
5.2.1 两个树是否相等
- 思考:
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
- 步骤:
-
- 1.
-
-
-
- 3.
-
- 注意:
class Solution {
/* 1.如果其中之一NULL,则该判断另一个子树是否为NULL
* 2.当前两值是否相等,递归判定其左右子树
*/
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==NULL) return q==NULL;
if(q==NULL) return p==NULL;
return p->val==q->val&&isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
};
//非递归版本 借用栈来实现
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==NULL)return q==NULL;
if(q==NULL) return p==NULL;
stack<TreeNode* > stk;
stk.push(q);
stk.push(p);
while(!stk.empty())
{
p=stk.top();
stk.pop();
q=stk.top();
stk.pop();
if(p==NULL&&q==NULL) continue;
if(p==NULL||q==NULL) return false;
if(p->val!=q->val) return false;
stk.push(q->right);
stk.push(p->right);
stk.push(q->left);
stk.push(p->left);
}
return true;
}
};
5.2.2 判断树是否对称
- **思考**:
- **步骤**:
* 1.
* 2.
*
*
*
* 3.
- **注意**:
class Solution {
public:
bool isSymmetric(TreeNode *root) {
if(root==NULL) return true;
return helper(root->left,root->right);
}
bool helper(TreeNode * p, TreeNode * q){
if(p==NULL) return q==NULL;
if(q==NULL) return p==NULL;
return p->val==q->val&&helper(p->left,q->right)&&helper(p->right,q->left);
}
};
// 非递归版本
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return isSymmetric(root->left, root->right);
}
bool isSymmetric(TreeNode* p, TreeNode* q) {
if(!p&&!q) return true;
stack<TreeNode* > stk;
stk.push(q);
stk.push(p);
while(!stk.empty()){
p=stk.top();
stk.pop();
q=stk.top();
stk.pop();
if(!p&&!q) continue;
if(!p||!q) return false;
if(p->val!=q->val) return false;
stk.push(q->right);
stk.push(p->left);
stk.push(q->left);
stk.push(p->right);
}
return true;
}
};
5.2.3 二叉树是否平衡 Validate Binary Search Tree
Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.
class Solution {
public:
bool isBalanced(TreeNode *root) {
int height = getHeight(root);
if(height==-1)
return false;
return true;
}
int getHeight(TreeNode * root) {
if(root==NULL) return 0;
int left = getHeight(root->left);
int right =getHeight(root->right);
if(left==-1||right==-1||abs(left-right)>1) return -1;
return max(left,right)+1;
}
};
5.2.4 二叉搜索树是否合法 Validate Binary Search Tree
Description :
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.
思考: 中序遍历,当前值大于中序遍历的last 值,全部成立即可,那么怎么获取中序遍历的最后一个之呢,使用引用
class Solution {
public:
bool isValidBST(TreeNode* root) {
if(root==NULL)
return true;
bool mark=true;
int last=0;
help(root,mark,last);
}
bool help(TreeNode* root, bool& first, int &last){
if(root==NULL) return true;
bool templeft = help(root->left,first,last); // 遍历左子树,同时返回遍历的最后一个值
if(!templeft) return false; // 左子树不合法,则返回false
if(first){ // 当前节点是第一个值,这不比较
first=false;
} else if(last>=root->val) // 不是第一个节点则比较
return false;
last = root->val; //更新已遍历的最后一个值
return help(root->right,first,last); // 遍历右子树
}
};
5.3 树的路径与深度
5.3.1 二叉树的最小深度 letcode 111 Minimum Depth of Binary Tree
Description:
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
思考:
1.二叉树的广度优先遍历,利用队列,直到找到一个叶子节点,则停止循环。
2.递归的解法: 只有叶子节点才算深度,如果为叶子节点,则返回1,如果非叶子节点,但其中左右子树为NULL,则返回另一个为空的子树的深度,若左右子树都不为NULL,则返回两者中小的+1;
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==NULL) return 0;
if(root->left==NULL&&root->right==NULL) return 1;
if(root->left==NULL)return minDepth(root->right)+1;
if(root->right==NULL) return minDepth(root->left)+1;
return min(minDepth(root->left),minDepth(root->right))+1;
}
};
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==NULL)return 0;
vector<TreeNode* > vec;
vec.push_back(root);
int ret=0;
while(!vec.empty()){
ret++;
vector<TreeNode* >temp;
for(int i=0;i<vec.size();i++){
if(vec[i]->left!=NULL)
temp.push_back(vec[i]->left);
if(vec[i]->right!=NULL)
temp.push_back(vec[i]->right);
if(vec[i]->left==NULL&&vec[i]->right==NULL)
return ret;
}
vec=temp;
}
return ret;
}
};
5.3.2 二叉树的最大高度 leetcode 104
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL)return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
5.3.3 是否存在和为定值的路径 leetcode 112
Description:
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
For example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if(root==NULL) return false;
if(root->left==NULL&&root->right==NULL) {
if(sum==root->val)
return true;
else return false;
}
return hasPathSum(root->left,sum-root->val)||
hasPathSum(root->right,sum-root->val);
}
};
5.3.4 Binary Tree Maximum Path Sum leetcode 124
class Solution {
public:
int maxPathSum(TreeNode* root) {
if(root==NULL) return 0;
int m=root->val;
getSum(root,m);
return m;
}
int getSum(TreeNode * root ,int &m){
if(root==NULL) return 0;
int left = getSum(root->left,m);
int right =getSum(root->right,m);
int ret =max(max(left ,right),0)+root->val; //经过当前节点的长路径,左,右,仅有当前节点
m=max(max(ret,m),left+right+root->val); // 横跨当前节点的最长路径
return ret;
}
};
5.4 树的构造与变换
5.4.1 Flatten Binary Tree to Linked List
实际上的先序遍历变为链表
class Solution {
public:
void flatten(TreeNode* root) {
if(root==NULL) return ;
stack<TreeNode* > stk;
stk.push(root);
TreeNode te(0);
TreeNode* dummy=&te;
TreeNode* tail=dummy;
TreeNode * current;
while(!stk.empty()){
current =stk.top();
stk.pop();
if(current->right)
stk.push(current->right);
if(current->left)
stk.push(current->left);
tail->right=current;
tail=current;
tail->left =NULL;
tail->right =NULL;
}
root=dummy->right;
}
};
5.4.2 Populating Next Right Pointers in Each Node
- **思考**:
1.立即想到使用广搜,记录每一层的链表尾节点,但需要有一个 vector<TreeLinkNode* > 来记录每一层的尾节点,不符合题目的常数空间的要求
2. 递归调用,对每一层已经链接好的链表,遍历其中每个节点,操纵他们的子节点
- 步骤:
-
- 1.
-
-
-
- 3.
-
- 注意:
// 采用广度优先遍历的思想
class Solution {
public:
void connect(TreeLinkNode *root) {
vector<TreeLinkNode* > ret;
helper(root, ret,0);
}
void helper(TreeLinkNode* root , vector<TreeLinkNode* > &ret, int level){
if(root==NULL) return;
if(level+1>ret.size())
ret.push_back(root);
else{
ret[level]->next=root;
ret[level]=root;
}
helper(root->left ,ret,level+1);
helper(root->right, ret,level+1);
}
};
class Solution {
public:
void connect(TreeLinkNode *root) {
if(root==NULL||root->left==NULL) return;
TreeLinkNode* p=root;
TreeLinkNode* tail=root->left; //下一层链表的队尾
while(p!=NULL){
if(p==root){
p->left->next =p->right;
}
else {
tail->next=p->left;
p->left->next =p->right;
}
tail =p->right;
p=p->next;
}
connect(root->left);
}
};
5.4.3 Populating Next Right Pointers in Each Node II
class Solution {
public:
void connect(TreeLinkNode *root) {
vector<TreeLinkNode* > ret;
helper(root, ret,0);
}
void helper(TreeLinkNode* root , vector<TreeLinkNode* > &ret, int level){
if(root==NULL) return;
if(level+1>ret.size())
ret.push_back(root);
else{
ret[level]->next=root;
ret[level]=root;
}
helper(root->left ,ret,level+1);
helper(root->right, ret,level+1);
}
};
//递归版本
class Solution {
public:
void connect(TreeLinkNode *root) {
if(root==NULL) return;
TreeLinkNode* p=root;
TreeLinkNode temp(0);
TreeLinkNode* tail=&temp;
while(p!=NULL){
if(p->left==NULL&&p->right==NULL){
p=p->next;
continue;
}
else if(p->left!=NULL&&p->right!=NULL){
tail->next =p->left;
p->left->next=p->right;
tail=p->right;
}
else {
tail->next = (p->left!=NULL)?p->left:p->right;
tail=tail->next;
}
p=p->next;
}
connect(temp.next);
}
};
//迭代版本
class Solution {
public:
void connect(TreeLinkNode *root) {
if(root==NULL) return;
TreeLinkNode* p;
// 迭代版本
while(root!=NULL){
TreeLinkNode temp(0);
TreeLinkNode* tail=&temp;
p=root;
while(p!=NULL){
if(p->left==NULL&&p->right==NULL){
p=p->next;
continue;
}
else if(p->left!=NULL&&p->right!=NULL){
tail->next =p->left;
p->left->next=p->right;
tail=p->right;
}
else {
tail->next = (p->left!=NULL)?p->left:p->right;
tail=tail->next;
}
p=p->next;
}
root=temp.next;
}
}
};
5.4.4 Binary Search Tree Iterator
维护一个结构从开头每次调用next,返回中序遍历下一个节点
思考:
用栈s保存每个根节点——一条路径
cur表示当前要考虑的根节点
cur 一直往左走,走过的节点入栈
最后一个出栈(无左子树),访问它,它就是下一个要考虑的节点, cur = s.top()
cur = cur->right;
注意缓存,如果调用两次hasNext不应该改变结果
个人思考: 实际上是中序遍历的迭代版本
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class BSTIterator {
public:
BSTIterator(TreeNode *root) {
while(root!=NULL){
mystack.push(root);
root=root->left;
}
}
/** @return whether we have a next smallest number */
bool hasNext() {
return !mystack.empty();
}
/** @return the next smallest number */
int next() {
TreeNode* temp=mystack.top();
mystack.pop();
TreeNode* p;
if(temp->right!=NULL){
p=temp->right;
while(p!=NULL){
mystack.push(p);
p=p->left;
}
}
return temp->val;
}
private :
stack<TreeNode* > mystack;
};
/**
* Your BSTIterator will be called like this:
* BSTIterator i = BSTIterator(root);
* while (i.hasNext()) cout << i.next();
*/
5.4.5 Construct Binary Tree from Preorder and Inorder Traversal Leetcode 105
给定二叉树前、中序遍历,构造二叉树 (Leetcode 105)
分析:
前序遍历序列第一个是根节点x
从中序遍历序列中找到根节点x
中序遍历中x的左边序列对应等长的前序遍历序列
左子树
中序遍历中x的右边序列对应等长的前序遍历序列
右子树
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return helper(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
}
TreeNode* helper(vector<int>& preorder, vector<int>& inorder ,int pl,int ph ,int il,int ih){
if(pl>ph) return NULL;
TreeNode * root = new TreeNode(preorder[pl]);
int i=il;
for( ;i<=ih;i++){
if(inorder[i]==preorder[pl])
break;
}
int leftlen=i-il;
int rightlen=ih-i;
root->left = helper(preorder,inorder,pl+1,pl+leftlen,il,i-1);
root->right =helper(preorder,inorder,pl+leftlen+1,ph,i+1,ih);
return root;
}
};
5.4.6 Construct Binary Tree from Inorder and Postorder Traversal leetcode 106
定二叉树后、中序遍历,构造二叉树
后序遍历序列最后一个是根节点x
从中序遍历序列中找到根节点x
中序遍历中x的左边序列对应等长的后序遍历序列
左子树
中序遍历中x的右边序列对应等长的后序遍历序列
右子树
class Solution {
public:
TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
if(inorder.size()==0) return NULL;
int N = inorder.size();
TreeNode * ret= helper(inorder, postorder, 0,N-1 ,0,N-1)
return ret;
}
TreeNode * helper(vector<int> &inorder, vector<int> &postorder, int instart ,int inend ,int postart,int poend) {
if(instart==inend) return new TreeNode(inorder[instart]);
if(instart>inend) return NULL;
int last = postorder[poend];
TreeNode * ret = new TreeNode(last);
int mid=instart;
for(int i=instart ;i<=inend ;i++)
if(inorder[i]==last){
mid= i;
break;
}
ret->left= helper(inorder,postorder, instart,mid-1,postart,postart+(mid-1-instart));
ret->right = helper(inorder,postorder, mid+1,inend,postart+(mid-1-instart)+1,poend-1);
return ret;
}
};
5.4.7 Convert Sorted Array to Binary Search Tree leetcode108
Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return helper(nums,0,nums.size()-1);
}
TreeNode* helper(vector<int>& nums, int start,int end){
if(start>end) return NULL;
int mid =start+(end-start)/2;
TreeNode* root=new TreeNode(nums[mid]);
root->left=helper(nums,start,mid-1);
root->right =helper(nums,mid+1,end);
return root;
}
};