Google模拟面试【面试】
2023-12-25 16:00:42
Prompt #1
给一个二叉树,定义深度为结点到根;所要遍历的边的数量。
示例二叉树中8的深度为3,1的深度为0。
编写函数返回这个二叉树的所有结点的深度和。
示例二叉树答案是16
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
public class Main {
static class Node{
int val;
Node left;
Node right;
public Node(int v){
val=v;
}
}
public static void main(String[] args) {
Node a=new Node(1);
Node b=new Node(2);
Node c=new Node(3);
Node d=new Node(4);
Node e=new Node(5);
Node f=new Node(6);
Node g=new Node(7);
Node h=new Node(8);
Node i=new Node(9);
a.left=b;
a.right=c;
b.left=d;
b.right=e;
c.left=f;
c.right=g;
d.left=h;
d.right=i;
int res1=solve1(a);
System.out.println(res1);//16
}
public static int solve1(Node root){
sum=0;
sumDepths(root,0);
return sum;
}
static int sum;
public static void sumDepths(Node root,int depth){
sum+=depth;
if(root.left!=null){
sumDepths(root.left,depth+1);
}
if(root.right!=null){
sumDepths(root.right,depth+1);
}
}
}
Prompt #2
返回每一个结点的子树深度的和,求和
示例二叉树答案是26
树型dp
对于结点x,有两个孩子,y,z
x子树结点个数=1+y的子树结点个数+z的子树结点个数
x子树深度和=(y的子树结点个数+y的子树深度和)+(z的子树结点个数+z的子树深度和)
因为对于孩子y的每个结点来说,其对于y的双亲x的深度都是加了x->y的一条边。
特殊:叶子结点(1,0)
过程分析
8,9,5,6,7:(1,0)
4,3:(3,2)
2:(5,6)
1:(9,16)
2+2+6+16=26
public static int solve2(Node root) {
ans=0;
dfs(root);
return ans;
}
static class Info{
int numNodes;
int sumDepths;
public Info(int a,int b){
numNodes=a;
sumDepths=b;
}
}
static int ans;
static Info dfs(Node root){
Info pInfo=new Info(1,0);
if(root.left!=null){
Info cInfo=dfs(root.left);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
if(root.right!=null){
Info cInfo=dfs(root.right);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
ans+= pInfo.sumDepths;
return pInfo;
}
Prompt #3
求出所有节点到目标结点的深度和
比如到4的深度和是18
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
分析可以得出
到一个目标结点的深度和=
到根结点的目标和-子树中的结点数量+其他结点数量(子树之外的结点数)
其他结点数量=总结点数量-子树结点数量
dfs1把每个子树及其对应的结点数存入到map中
运行结果
<Node1,9>,<Node2,5>,<Node3,3>,<Node4,3>
<Node5,1>,<Node6,1>,<Node7,1>,<Node8,1>,<Node9,1>,
n=root.numNodes=9
sumDists=root.sumDepth=16
模拟运行,忽略其他结点
dfs2(1,16,4)
左分支:newDists=16-5+(9-5)=15
dfs2(2,15,4)
右分支:newDists=15-3+(9-3)=18
dfs(4,18,4)
ans=18
会继续遍历所有结点,但是答案只会保存一个
//视频中把每个子树的结点数信息放到结点中
//我把其放到哈希表中
static HashMap<Node,Integer> map;
//总结点个数
static int n;
static int solve3(Node root,Node target){
ans=0;
map=new HashMap<>();
sumDists(root,target);
return ans;
}
//把每个子树的结点数放到对应结点和结点数的map中
static Info dfs1(Node root){
Info pInfo=new Info(1,0);
if(root.left!=null){
Info cInfo=dfs1(root.left);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
if(root.right!=null){
Info cInfo=dfs1(root.right);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
//和dfs的区别只有此处
map.put(root, pInfo.numNodes);
return pInfo;
}
static void dfs2(Node u,int sumDists,Node target){
if(u==target){
ans=sumDists;
}
if(u.left!=null){
int newSumDists=sumDists-map.get(u.left)+(n-map.get(u.left));
dfs2(u.left,newSumDists,target);
}
if(u.right!=null){
int newSumDists=sumDists-map.get(u.right)+(n-map.get(u.right));
dfs2(u.right,newSumDists,target);
}
}
static int sumDists(Node root,Node target){
Info info=dfs1(root);
n=info.numNodes;
dfs2(root,info.sumDepths,target);
return ans;
}
补充 #3用图来解决
到4的深度和为18
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
2,8,9到4的深度都是1
1,5到4的深度都是2
3到4的深度是3
6,7到4的深度都是4
1*3+2*2+3+2*4=18
一个bfs
//用图的方法解决
//设置访问数组
static HashMap<Node,Boolean> visited;
static int solve(Node root,Node target){
ans=0;
visited=new HashMap<>();
//图,hashmap可以更快找到,而没有采取下标对应结点
HashMap<Node,ArrayList<Node>> graph=new HashMap<>();
//树转为双向图,并且设置访问数组
toGraph(root,graph);
//广度优先遍历
bfs(graph,target);
return ans;
}
//深度优先转为双向图
static void toGraph(Node root,HashMap<Node,ArrayList<Node>> graph){
if(!graph.containsKey(root)){
graph.put(root,new ArrayList<>());
}
if(root.left!=null){
graph.get(root).add(root.left);
toGraph(root.left,graph);
graph.get(root.left).add(root);
}
if(root.right!=null){
graph.get(root).add(root.right);
toGraph(root.right,graph);
graph.get(root.right).add(root);
}
visited.put(root,false);
}
static void bfs(HashMap<Node,ArrayList<Node>> graph,Node target){
visited.put(target,true);
Queue<Node> queue=new ArrayDeque<>();
//加入第一层
for (Node v:graph.get(target)){
queue.offer(v);
}
//第一层深度为1
int height=1;
while (!queue.isEmpty()){
int size=queue.size();
//每次遍历一层
for (int i = 0; i < size; i++) {
Node v=queue.poll();
if (!visited.get(v)){
//设置访问数组
visited.put(v,true);
//记录答案
ans+=height;
//下一层添加
for (Node next:graph.get(v)) {
queue.offer(next);
}
}
}
//下一次深度+1
height++;
}
}
所有代码
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Queue;
public class Main {
static class Node{
int val;
Node left;
Node right;
public Node(int v){
val=v;
}
}
public static void main(String[] args) {
Node a=new Node(1);
Node b=new Node(2);
Node c=new Node(3);
Node d=new Node(4);
Node e=new Node(5);
Node f=new Node(6);
Node g=new Node(7);
Node h=new Node(8);
Node i=new Node(9);
a.left=b;
a.right=c;
b.left=d;
b.right=e;
c.left=f;
c.right=g;
d.left=h;
d.right=i;
int res1=solve1(a);
System.out.println(res1);//16
int res2=solve2(a);
System.out.println(res2);//26
int res3=solve3(a,d);
System.out.println(res3);//18
//使用图来解决#3
int res=solve(a,d);
System.out.println(res);//18
}
//--------------------------------------------------------------------
public static int solve1(Node root){
sum=0;
sumDepths(root,0);
return sum;
}
static int sum;
public static void sumDepths(Node root,int depth){
sum+=depth;
if(root.left!=null){
sumDepths(root.left,depth+1);
}
if(root.right!=null){
sumDepths(root.right,depth+1);
}
}
//--------------------------------------------------------------------
public static int solve2(Node root) {
ans=0;
dfs(root);
return ans;
}
static class Info{
int numNodes;
int sumDepths;
public Info(int a,int b){
numNodes=a;
sumDepths=b;
}
}
static int ans;
static Info dfs(Node root){
Info pInfo=new Info(1,0);
if(root.left!=null){
Info cInfo=dfs(root.left);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
if(root.right!=null){
Info cInfo=dfs(root.right);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
ans+= pInfo.sumDepths;
return pInfo;
}
//--------------------------------------------------------------------
//视频中把每个子树的结点数信息放到结点中
//我把其放到哈希表中
static HashMap<Node,Integer> map;
//总结点个数
static int n;
static int solve3(Node root,Node target){
ans=0;
map=new HashMap<>();
sumDists(root,target);
return ans;
}
//把每个子树的结点数放到对应结点和结点数的map中
static Info dfs1(Node root){
Info pInfo=new Info(1,0);
if(root.left!=null){
Info cInfo=dfs1(root.left);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
if(root.right!=null){
Info cInfo=dfs1(root.right);
pInfo.sumDepths+=cInfo.sumDepths+cInfo.numNodes;
pInfo.numNodes+=cInfo.numNodes;
}
//和dfs的区别只有此处
map.put(root, pInfo.numNodes);
return pInfo;
}
static void dfs2(Node u,int sumDists,Node target){
if(u==target){
ans=sumDists;
}
if(u.left!=null){
int newSumDists=sumDists-map.get(u.left)+(n-map.get(u.left));
dfs2(u.left,newSumDists,target);
}
if(u.right!=null){
int newSumDists=sumDists-map.get(u.right)+(n-map.get(u.right));
dfs2(u.right,newSumDists,target);
}
}
static int sumDists(Node root,Node target){
Info info=dfs1(root);
n=info.numNodes;
dfs2(root,info.sumDepths,target);
return ans;
}
//--------------------------------------------------------------------
//用图的方法解决
//设置访问数组
static HashMap<Node,Boolean> visited;
static int solve(Node root,Node target){
ans=0;
visited=new HashMap<>();
//图,hashmap可以更快找到,而没有采取下标对应结点
HashMap<Node,ArrayList<Node>> graph=new HashMap<>();
//树转为双向图,并且设置访问数组
toGraph(root,graph);
//广度优先遍历
bfs(graph,target);
return ans;
}
//深度优先转为双向图
static void toGraph(Node root,HashMap<Node,ArrayList<Node>> graph){
if(!graph.containsKey(root)){
graph.put(root,new ArrayList<>());
}
if(root.left!=null){
graph.get(root).add(root.left);
toGraph(root.left,graph);
graph.get(root.left).add(root);
}
if(root.right!=null){
graph.get(root).add(root.right);
toGraph(root.right,graph);
graph.get(root.right).add(root);
}
visited.put(root,false);
}
static void bfs(HashMap<Node,ArrayList<Node>> graph,Node target){
visited.put(target,true);
Queue<Node> queue=new ArrayDeque<>();
//加入第一层
for (Node v:graph.get(target)){
queue.offer(v);
}
//第一层深度为1
int height=1;
while (!queue.isEmpty()){
int size=queue.size();
//每次遍历一层
for (int i = 0; i < size; i++) {
Node v=queue.poll();
if (!visited.get(v)){
//设置访问数组
visited.put(v,true);
//记录答案
ans+=height;
//下一层添加
for (Node next:graph.get(v)) {
queue.offer(next);
}
}
}
//下一次深度+1
height++;
}
}
}
2023-12-25 19:10:43