Google模拟面试【面试】

Google模拟面试【面试】

2023-12-25 16:00:42

Google代码面试

Prompt #1

给一个二叉树,定义深度为结点到根;所要遍历的边的数量。

示例二叉树中8的深度为3,1的深度为0。

编写函数返回这个二叉树的所有结点的深度和。

示例二叉树答案是16

复制代码
         1
        /  \
      2      3
     / \    / \
    4   5  6   7
   / \
  8   9
java 复制代码
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

java 复制代码
	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中

运行结果

java 复制代码
<Node1,9>,<Node2,5>,<Node3,3>,<Node4,3>
<Node5,1>,<Node6,1>,<Node7,1>,<Node8,1>,<Node9,1>,
java 复制代码
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

会继续遍历所有结点,但是答案只会保存一个

java 复制代码
   //视频中把每个子树的结点数信息放到结点中
    //我把其放到哈希表中
    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
java 复制代码
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

java 复制代码
    //用图的方法解决
    //设置访问数组
    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++;
        }
    }

所有代码

java 复制代码
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

相关推荐
Lee川22 分钟前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i2 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有3 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有3 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫4 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫4 小时前
Handler基本概念
面试
Gorway4 小时前
解析残差网络 (ResNet)
算法
Wect4 小时前
浏览器缓存机制
前端·面试·浏览器
拖拉斯旋风4 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect4 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript