目录
例1.给定二叉树的前序遍历和中序遍历,构造二叉树 LC-105
例2.二叉树的高度、最小深度、二叉搜索树(BST)判断、对称判断、平衡判断
图论简介
面试题总体分析
图:
连通性(割点、边)、 最小生成树 、最短路 、 搜索(BFS、DFS) 、 欧拉回路 、 哈密尔顿回路 、 拓扑排序
树:
树的定义与判断 、、 平衡,二叉搜索树、最大(小)深度 、最近公共祖先(LCA)
一些例题:
例1.给定二叉树的前序遍历和中序遍历,构造二叉树 LC-105
分析:前序遍历的第一个节点是根节点,在中序遍历中找到根节点,并把中序遍历分为左子树+右子树
注意 下标范围
class Solution{
public:
TreeNode * dfs(vector<int> &preorder, vector<int> &inorder,int pre, int in, int len){
if(len==0) return null;
TreeNode * root=new TreeNode(preorder[pre]); //树根节点为前序遍历的第一个节点
int i;
for(i=in;inorder[i]!=preorder[pre];i++); //在中序遍历中找到根节点
root->left=dfs(preorder,inorder,pre+1,in,i-in); // pre开始 in开始
root->right=dfs((preorder,inorder,pre+1+i-in,i+1,len-1-i+in)
return root;
}
TreeNode * buildTree(vector<int> &preorder, vector<int> &inorder ){
return dfs(preorder,inorder,0,0,inorder.size());
}
}
例2.二叉树的高度、最小深度、二叉搜索树(BST)判断、对称判断、平衡判断
【用同一个递归框架解决】
LC-124:二叉树每个节点有一个权重,计算 和最大的路径
递归计算左子树 递归计算右子树,master计算max(左)+max(右)+root->value 注意返回值与最大值的关系
class Solution{
public:
int dfs(TreeNode * root,int &m){
if(root==null) return 0;
int left=dfs(root->left,m);
int right=dfs(root->right,m);
int ret=max(max(left,right),0)+root->val; //不含跨界的 求root向下延伸的最长路径
m=max( max(m,ret),left+right+root->val); //含跨界的
return ret;
}
int maxPathSum(TreeNode * root){
if(root==null) return 0;
return dfs(root, root->val);
}
};
leetcode-111 二叉树的最小深度 注意空子树
class Solution{
public:
int minDepth(TreeNode * root){
if(root==null) return 0; //00
if(root->left){
if(root->right){ //11
return min( minDepth(root->left),minDepth(root->right) )+1;
}else{ //10
return minDepth(root->left)+1;
}
}else if(root->right){ //01
return minDepth(root->right)+1;
}else{ //only root
return 1;
}
}
};
Leetcode-110 判断平衡
class Solution{
public:
bool dfs(TreeNode * root,int &height){ //判断是否平衡
if(root==null) {height=0; return true;}
int h1,h2;
if(!dfs(root->left,h1))
return false;
if(!dfs(root->right,h2))
return false;
height=max(h1,h2)+1; //记录最大树高
return (h1-h2)>=-1 && (h1-h2)<=1; //|h1-h2|<=1
}
bool isBalanced(TreeNode * root){
int height; //树高
return dfs(root,height);
}
};
Leetcode-104 最大深度
class Solution{
public:
int maxDepth(TreeNode * root){
return root?max( maxDepth(root->left),maxDepth(root->right))+1 : 0;
}
};
Leetcode-100 判断相同
class Solution{
public:
bool isSameTree(TreeNode *p,TreeNode *q){
if(p==null) return q==null;
if(q==null) return false;
return (p->val)==(q->val) && isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
};
Leetcode-98 判断二叉搜索树 √ 【BST 中序遍历 存到vector中 判断是否是递增的 / 在递归的时候判断】
class Solution{
public:
bool dfs(TreeNode * root, bool &first, int &last){ //判断BST 中序遍历
if(root==0) return true; //空树是bst
if(!dfs(root->left,first,last)){
return false;
}
if(first){
first=false;
last=root->val;
}else if(last>=root->val){ //左中右 中>=左 右>=中 last代表上一个遍历的节点
return false;
}
last=root->val;
bool flg=dfs(root->right,first,last);
return flg;
}
bool isValidBST(TreeNode * root){\
bool mark=true; int val=0
return dfs(root,mark,val); //mark表示一上来还没有遍历过任何节点
}
};
例3.二叉树与链表转换
Leetcode-114 二叉树转链表 [还是用中序遍历的框架,中间操作如下:]
class Solution{
public:
void dfs(TreeNode *&root,TreeNode *&last){
last=root;
if(root==null) return ;
TreeNode *mylast,*tmp=root->right;
dfs(root->left,mylast); //左
if(mylast){
last=mylast; //中
last->right=tmp;
root->right=root->left;
root->left=null;
}
dfs(tmp,mylast); //右
if(mylast)
last=mylast;
}
void flatten(TreeNode * root){
TreeNode *last;
dfs(root,last);
}
};
链表转(平衡)二叉树
LC-109 :有序链表转换为二叉搜索树
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
方法1. O(nlogn) 因为链表不能随机访问 如果是数组转为二叉树 O(logn)
class Solution{ //LC-109 有序链表转换为二叉搜索树
public:
TreeNode *dfs(ListNode *head, int len){
if(len==0) return null;
listNode *now=head;
for(int (i=len-1)>>1; i; i--){ //O(n)
now=now->next;
} //链表1/2的位置是 root
TreeNode * root=new TreeNode(now->val);
root->left=dfs(head,(len-1)>>1);
root->right=dfs(now->next,len>>1)
return root;
}
TreeNode *sortedListToBST(ListNode * head){
ListNode * tmp=head;
int len;
for(len=0; tmp; tmp=tmp->next,++len);
return dfs(head,len);
}
};
方法2.优化,同时移动指针O(n) 【中序遍历框架,下图为核心操作】 T(n)=2T(n/2)+O(1)
class Solution{ //LC-109 有序链表转换为平衡二叉搜索树
public:
TreeNode *dfs(ListNode *head, int len){
if(len==0) return null;
int num=(len-1)>>1;
TreeNode * left=dfs(head,num);
TreeNode * root=new TreeNode(head->val); //中序遍历 核心操作 如图
root->left=left;
head=head->next;
root->right=dfs(head,len-num-1);
return root;
}
TreeNode *sortedListToBST(ListNode * head){
ListNode * tmp=head;
int len;
for(len=0; tmp; tmp=tmp->next,++len);
return dfs(head,len);
}
};
练习:LC-108 有序数组转(平衡)二叉树
例4.无向图复制
复制一个有向图,(邻接表存储)分析:DFS,图中可能有圈
class Solution{
public:
UnDirectedGraphNode * dfs(const UnDirectedGraphNode *node, map<int, UnDirectedGraphNode *> &have){
map<int, UnDirectedGraphNode *>::iter t=have.find(node->label);
if(t==have.end()){ //未找到
UnDirectedGraphNode *newnode=new UnDirectedGraphNode(node->label);
have.insert(make_pair(node->label,newnode));
for(int i=0;i<node.neighbors.size();i++){
newnode->neighbors.push_back(dfs(node->neighbors[i],have));
}
return newnode;
}else{
return t->second; //UnDirectedGraphNode *
}
}
UnDirectedGraphNode *cloneGraph(UnDirectedGraphNode * node){
map<int,UnDirectedGraphNode *> have;
if(node==null) return null;
return dfs(node,have);
}
};
例5.直角路线遍历棋盘
构造二部图:图中每个点(x,y)的横坐标放到集合X中,纵坐标放到Y中;坐标(x,y)有边,寻找欧拉路
判断欧拉路:除了起点终点,其余点的出度=入度 ;
总结
理解递归
熟悉树的遍历 (递归、非递归)
其他问题:
LCA最近公共祖先(二叉树、非二叉树、二叉搜索树、离线算法——在线算法)
(隐式)图搜索bfs+dfs、——强联通分量
拓扑排序(较少)
来源:CSDN
作者:weixin_43107805
链接:https://blog.csdn.net/weixin_43107805/article/details/104600795