美文网首页
20200721 网易互娱ME提前批笔试(未允禁转)

20200721 网易互娱ME提前批笔试(未允禁转)

作者: 9_SooHyun | 来源:发表于2020-07-22 14:34 被阅读0次

    20200721 网易互娱ME提前批笔试 4编程

    1.翻转一棵多叉树。该多叉树的每个结点的val唯一

    多叉树按照先序遍历的顺序,以数组的方式记录。数组的每个元素以数组表示每个treenode,如:[1,0]表示当前结点的val是1,其父结点的val是0,这里规定根节点的父结点总是0。下面的例子表示一棵双层的三叉树
    [[1,0], [2,1], [3,1], [4,1]]

    思路:
    因为树是递归的,一棵树的子树也是树,子树的子树也是树。翻转一棵树,从图像上看=颠倒它的每一棵子树的位置,再递归地翻转每棵子树的子树;从代码上看,如果我对原多叉树进行“先后-左”顺序遍历,就是它的翻转后的树的先序遍历顺序

    本题拿到当时有两种思路
    1.先利用前序遍历的结果重建出一颗多叉树,然后对重建出来的多叉树按照“先右-左”的顺序遍历,得到的结果就是翻转后的结果,因为要对多叉树重建,当时直觉感觉比较麻烦,所以暂时搁置,第二天才复盘思考的
    因为是多叉树,那么TreeNode的结构只能是

    class TreeNode:
        def __init__(self, v):
            self.val = v
            self.father = None
            self.children = []
    

    通过list[TreeNode]来描述子节点

    根据先序遍历重建树,可以设计一个递归方法buildTree(node_data_list)实现
    递归的输入和输出是:接受整棵树的先序遍历序列node_data_list,返回建好的树的root;递归式是node.children.append(buildTree(sub_tree))
    每次我们需要在原先序遍历序列中找到各个子树对应的部分子序列,作为参数执行递归调用
    伪代码模板如下,实际上就两步,方便得很

    def buildTree(node_data_list):
        # 递归函数先写递归出口
        if not node_data_list:
            return 
        
        ## 第一步,build root -【首个结点必然作为node_data_list对应的树的根】 ##
        first_ele = node_data_list[0]
        ... build root_node base on first_ele ...
        
        ## 第二步,build every sub_tree and establish relation to root_node ##
        find every sub_tree data sequence from node_data_list
            for each sub_tree data sequence:
                root_node.children.append(buildTree(sub_tree))
                
        return root_node
    

    整个实现的代码如下

    class TreeNode:
        def __init__(self, v):
            self.val = v
            self.father = None
            self.children = []
    
    class Solution:
        def invert_tree(self , node_data_list):
            l = len(node_data_list)
            # 边界条件
            if l <= 1:
                return node_data_list
            
            root = self.buildTree(node_data_list, 0)
            res = []
            self.reverseOrder(root, res)
            return res
        
        # 建树,并返回树的根结点
        def buildTree(self, node_data_list, first_ele_father):
            if not node_data_list:
                return 
                
            first_ele = node_data_list[0]
            node = TreeNode(first_ele[0])
            node.father = first_ele_father
            
            sub_tree_start_index = 1
            for i in range(2, len(node_data_list)):
                ele = node_data_list[i]
                if ele[1] == first_ele[0]:
                    # 获取子树对应的数组数据
                    sub_tree = node_data_list[sub_tree_start_index:i]
                    sub_tree_start_index = i
                    # 对子树进行buildtree
                    sub_tree_root = self.buildTree(sub_tree, first_ele[0])
                    node.children.append(sub_tree_root)
            sub_tree = node_data_list[sub_tree_start_index:]
            sub_tree_root = self.buildTree(sub_tree, first_ele[0])
            node.children.append(sub_tree_root)
            return node
        
        # “先右-左”顺序访问一棵树
        def reverseOrder(self, root, res):
            if not root:
                return 
            
            res.append([root.val, root.father])
            for c in root.children[::-1]:
                self.reverseOrder(c, res)
                
    s = Solution()
    print(s.invert_tree([[1,0],[2,1],[5,2],[6,5],[7,5],[3,1],[4,1]]))
    
    1. 直接在先序遍历序列上找规律。通过分析发现,树翻转后的先序遍历结果,就是把各个子树对应的序列sub1,sub2,sub3... 倒置成 ...sub3,sub2,sub1,然后每个sub里再继续倒置,递归下去直至结束。这是我当时采用的解法
      递归函数设计
      输入输出:输入node_data_list int整型二维数组,输出翻转后的res,也是整型二维数组
      递归式:res = [node_data_list[0]] && res += self.invert_tree(node_dlist)
    # # 一次ac 40min
    # # 
    # # @param node_data_list int整型二维数组 
    # # @return int整型二维数组
    # #
    class Solution:
        def invert_tree(self , node_data_list ):
            l = len(node_data_list)
            # 递归出口
            if l <= 1:
                return node_data_list
    
            father_id = node_data_list[0][0]
            sub_tree = []
            end_index = l
            # 倒序方式找出各个子树集,就完成了各sub的倒置
            for i in range(l-1, 0, -1):
                if node_data_list[i][1] == father_id:
                    sub_tree.append(node_data_list[i:end_index])
                    end_index = i
            res = [node_data_list[0]]
            for node_dlist in sub_tree:
                # 递归调用
                res += self.invert_tree(node_dlist)
            return res
    
    
    s = Solution()
    print(s.invert_tree([[1,0],[2,1],[5,2],[6,5],[7,5],[3,1],[4,1]]))
    

    2. 查找运送情报路途中最危险城市

    给定n个城市,每个城市用1-n表示。城市1危险系数最高为1,离城市1越近的城市危险系数越高。城市之间有路径相连,且任意两个城市之间的路径唯一。输入一个整数road_num,描述地图中城市间通路的数量,接着输入road_num数量的二元组,如 1 2 表示城市1、2之间直接联通;再接下来输入整数targets,表示情报传送任务的数量,再输入targets个二元组,如 3 6 表示需要将情报送达城市3,4,5,6。要求打印每次情报传送任务中经过的最危险的城市

    思路:
    首先,需要描述整个地图,这里采用邻接字典 dict {city1:[nei1, nei2, ...], ...}结构,需要遍历所有城市通路,O(road_num)
    然后,根据邻接字典,通过BFS或DFS生成城市等级字典
    再者,定义一个函数,接受起始城市、目标城市和邻接字典,通过dfs返回它们的联通路径
    最后,对每一个target进行分解,如 3 6 ,分解为3-4,4-5,5-6,检查每一小组的联通路径并更新路径上的最危险城市(每一小组都要dfs查路径,复杂度就高了,但好像没有什么好办法)

    # ac 40 % 原因超时 1h10min,改不动
    
    # 生成邻接字典
    def genNeiborDict(roads):
        d = dict()
        for r in roads:
            a, b = r[0], r[1]
            if a not in d:
                d[a] = []
            if b not in d:
                d[b] = []
            
            if a not in d[b]:
                d[b].append(a)
            if b not in d[a]:
                d[a].append(b)
        return d
    
    # dfs,生成城市等级字典
    def genLevelDict(neibor_d):
        level_d = {1:1}
        s = set()
        s.add(1)
        def dfs(neibors, visited, level_to_assign):
            for n in neibors:
                if n not in visited:
                    level_d[n] = level_to_assign
                    visited.add(n)
                    dfs(neibor_d[n], visited, level_to_assign+1)
       
        dfs(neibor_d[1], s, 2)
        return level_d
    
    # dfs回溯定路径
    def getRoadMaxCity(neibor_d, a_road):
        start, end = a_road
        track = [start]
        found_flag = [False]
        final_track = []
        def backtracking(track, end, found_flag, final_track):
            if track[-1] == end:
                found_flag[0] = True
                for ele in track:
                    final_track.append(ele)
                return
            
            last_city = track[-1]
            for nex in neibor_d[last_city]:
                if nex not in track:
                    # 修改状态
                    track.append(nex)
                    backtracking(track, end, found_flag, final_track)
                    # 修回
                    track.pop(-1)
                    if found_flag[0]:
                        return
        backtracking(track, end, found_flag, final_track)
        return final_track
    
    ## 处理输入输出 ##
    import sys 
    content = list(sys.stdin)
    road_num = int(content[0].strip())
    roads = [content[i].strip().split() for i in range(1, road_num)]
    for i in range(road_num-1):
        roads[i] = [int(ele) for ele in roads[i]]
    
    target_num = int(content[road_num].strip())
    targets = [content[i].strip().split() for i in range(1+road_num, 1+road_num+target_num)]
    for i in range(target_num):
        targets[i] = [int(ele) for ele in targets[i]]
    # print(road_num, roads, target_num, targets)
    ## 处理输入输出完毕 ##
    
    neibor_d = genNeiborDict(roads)
    level_d = genLevelDict(neibor_d)
    for r in targets:
        lev, res_city = float('inf'), 0
        r.sort()
        begin_city = r[0]
        des_city = r[0] + 1
        while des_city <= r[1]:
            track = getRoadMaxCity(neibor_d, [begin_city, des_city])
            # print([begin_city, des_city], track)
            for t in track:
                if level_d[t] < lev:
                    lev = level_d[t]
                    res_city = t
            begin_city, des_city = des_city, des_city + 1
        print(res_city)
    

    3. 检查病毒类型

    没看,return 1 过了50多%骗分

    4. 并查集分类问题

    给一个list,包含所有元素
    再给一个二维list,每个元素是长度为2的list,表示2个ele为同类
    求最后分成几类

    思路:
    特征比较明显的并查集问题。时间不多,疯狂coding
    事后总感觉哪里不太对,回想发现并查集的findRoot(ele)方法写错了一个地方。。。导致一直死循环,然而已经提交,凉了
    这里罚重写一次

    class UFS:
        def __init__(self):
            self.father = dict()
            
        def findRoot(self, ele):
            ####!!!!醒醒!!是if 不是 while !!!!while就死循环了####
            if self.father[ele] != ele:
                self.father[ele] = self.findRoot(self.father[ele])
            return self.father[ele]
        
        def union(self, ele1, ele2):
            r1, r2 = self.findRoot(ele1), self.findRoot(ele2)
            if r1 != r2:
                self.father[r1] = r2
    

    相关文章

      网友评论

          本文标题:20200721 网易互娱ME提前批笔试(未允禁转)

          本文链接:https://www.haomeiwen.com/subject/njazkktx.html