华为通软|暑期实习|笔试合集

得空,整理一下之前搞懂了的一些笔试内容

04-19笔试

第一题.服务器能耗统计

  • 服务器有三种运行状态:空载、单任务、多任务,每个时间片的能耗的分别为134;
  • 每个任务由起始时间片和结束时间片定义运行时间:
  • 如果一个时间片只有一个任务需要执行,则服务器处于单任务状态;
  • 如果一个时间片有多个任务需要执行,则服务器处于多任务状态;
  • 给定一个任务列表,请计算出从第一个任务开始,到所有任务结束,服务器的总能耗。
  • 输入:一个只包含整数的二维数组:

  • 第一行的数字表示一共有多少个任务
  • 后续每行包含由空格分割的两个整数,用于确定每一个任务的起始时间片和结束时间片;
  • 任务执行时间包含起始和结束时间片,即任务执行时间是左闭右闭的;
  • 结束时间片一定大于等于起始时间片;
  • 时间片范围: [01000000]: 任务数范围: [1,10000];
  • 输出:一个整数,代表服务器的总能耗。

样例1

样例2

  • 思路:差分数组统计区间,然后遍历区间(因为区间只有100w,所以可以直接遍历),按规则叠加即可。
// 第一题
    // 时间复杂度O(n),空间复杂度O(max)
    let arr = [[2,5],[8,9]];
    let task1 = arr => {
        let max = 0;
        // 首先找到传入的任务中,最长的结束时间
        for(let i = 0; i < arr.length; i++){
            if(arr[i][1] > max) max = arr[i][1];
        }
        // 用最长的结束时间新建一个标记数组
        let visit = new Array(max + 1).fill(0);
        // 如果检测到是传入数据的左边界,visit对应+1,是右边界则减一,差分的思想
        for(let i = 0; i < arr.length; i++){
            visit[arr[i][0]]++;
            visit[arr[i][1]]--; 
        }
        // 分别用以中途计数,返回答案和标记是否已经有任务运行过
        let cnt = 0;
        let ans = 0;
        let flag = 0;
        for(let i = 0; i <= max; i++){
            // 注意这里是左闭右闭的区间,如果是右区间,应该先算值再进行加减
            // 如果是左区间和常规值,就需要先加减再计算
            if(visit[i] == - 1){
                if(cnt == 1){
                    ans += 3;
                    flag = 1;
                } else if(cnt >= 2){
                    ans += 4;
                } else if(cnt == 0 && flag){
                    ans += 1;
                }
                cnt += visit[i];
            } else {
                cnt += visit[i];
                if(cnt == 1){
                    ans += 3;
                    flag = 1;
                } else if(cnt >= 2){
                    ans += 4;
                } else if(cnt == 0 && flag){
                    ans += 1;
                }
            }
        }
        return ans;
    }
    // console.log(task1(arr))

第二题、 树上逃离

  • 给定一棵树,这个树有n个节点,节点编号从0开始依次递增,0固定为根节点。在这棵树上有一个小猴子,初始时该猴子位于根节点(0) 上,小猴子一次可以沿着树上的边从一个节点挪到另一个节点,但这棵树上有一些节点设置有障碍物,如果某个节点上设置了障碍物,小猴子就不能通过连接该节点的边挪动到该节点上。问小猴子是否能跑到树的叶子节点(叶子节点定义为只有一条边连接的节点),如果可以,请输出小猴子跑到叶子节点的最短路径(通过的边最少),否则输出字符串NULL
  • 输入
  • 第一行给出数字n,表示这个树有n个节点,节点编号从0开始依次递增,0固定为根节点,1<=n<10000
  • 第二行给出数字edge,表示接下来有edge行,每行是一条边
  • 接下来的edge行是边: x y,表示xy节点有一条边连接
  • 边信息结束后接下来的一行给出数字block,表示接下来有block行,每行是个障碍物
  • 接下来的block行是障碍物: X,表示节点x上存在障碍物
  • 输出
  • 如果小猴子能跑到树的叶子节点,请输出小猴子跑到叶子节点的最短路径(通过的边最少),比如小猴子从0经过1到达2 (叶子节点) ,那么输出“0->1->2”,否则输出“NULL”。注意如果存在多条最短路径,请按照节点序号排序输出,比如0->10->3两条路径,第一个节点0一样,则比较第二个节点1313小,因此输出0->1这条路径。再如 0->5->2->3 0->5->1->4,则输出 0->5-31->4

样例1

  • 解释: n=4,edge=[[0,1],[0,2],[0,3]],block=[2,3]表示一个有4个节点、3条边的树,其中节点2和节点3上有障碍物,小猴子能从0到达叶子节点1 (节点1只有一条边[1,0]和它连接,因此是叶子节点) ,即可以跑出这个树,所以输出为0->1

样例2

  • 解释: 节点4上有障碍物,因此0-3-4这条路不通,节点2和节点6都是叶子节点,但0->1->20->1->5->6路径短(通过的边最少) ,因此输出为0->1->2

样例3

  • 解释:节点1是叶子节点,但存在障碍物,因此小猴子无法到达叶子节点,输出NULL
  • 思路:典型最短路模型。使用bfs找到距离根最近的节点即可,注意要存储每个遍历状态经过的路径。
// 第二题
    // 时间复杂度,空间复杂度都是O(N + E)
    let task2 = (n, edge, block)=>{
        // 用map存邻接表
        let map = {};
        // 遍历edge数组,记录邻接表
        for(let i = 0; i < edge.length; i++){
            if(!map[edge[i][0]]){
                map[edge[i][0]] = [edge[i][1]];
            } else {
                map[edge[i][0]].push(edge[i][1]);
            }
        }
        // console.log(map)
        // bfs用的队列
        let queue = [];
        // 初始化压入[0]
        queue.push([0]);
        while(queue.length !== 0){
            // 取队头元素,这里是一个路径
            let curList = queue.shift();
            // 取路径的最后一个元素
            let cur = curList[curList.length - 1];
                // 因为前面已经确认了他不是叶子节点,所以可以直接遍历    
                for(let next of map[cur]){
                    // 如果不是障碍物,并且是叶子节点
                    if(!block.includes(next) && !map[next]){
                        // 直接返回
                        return [...curList, next].join('->');
                        // 否则压入队列
                    } else if(!block.includes(next) && map[next]){
                        queue.push([...curList, next]);
                    }
                }
        }
        // 对于为空的情况额外处理
        return null;
    }
    // console.log(task2(4,[[0,1],[0,2],[0,3]],[2,3]))

04-26笔试

第一题、批量初始化次数

  • 某部门在开发一个代码分析工具,需要分析模块之间的依赖关系,用来确定模块的初始化顺序、是否有循环依赖等问题。"批量初始化”是指一次可以初始化一个或多个模块。例如模块1依赖模块2,模块3也依赖模块2,但模块13没有依赖关系,则必须先"批量初始化”模块2,再"批量初始化"模块13。现给定一组模块间的依赖关系,请计算需要“批量初始化"的次数。
  • 输入
  • (1)1行只有一个数字.表示模块总数N
  • (2)随后的N行依次表示模块1N的依赖数据。每行的第1个数表示依赖的模块数量(不会超过N),之后的数字表示当前模块依赖的ID序列。该序列不会重复出现相同的数字,模块ID的取值定在[1,N]之内。
  • (3)模块总数N取值范围 1<=N<=1000.
  • (4)每一行里面的数字按1个空格分隔。
  • 输出
  • 输出“批量初始化次数”.若有循环依赖无法完成初始化,则输出-1

样例1

样例2:

  • 思路:拓扑排序模拟即可。
// 4.26第一题
    // 时间复杂度O(n),空间复杂度O(n)
    const task3 = (n,arr)=> {
        let inDegree = new Array(n + 1).fill(0);
        let map = {};
        for(let i = 0; i < arr.length; i++){
            let len = arr[i].length;
            for(let j = 0; j < len; j++){
                if(j == 0){
                    inDegree[i + 1] = arr[i][j];
                    continue;
                } 
                if(!map[arr[i][j]]){
                    map[arr[i][j]] = [i + 1];
                } else {
                    map[arr[i][j]].push(i + 1);
                }
            }
        }
        console.log(map,inDegree)
        let depth = 0;
        let queue = [];
        for(let i = 1; i <= n; i++){
            if(inDegree[i] == 0){
                queue.push(i);
            }
        }
        let cnt = 0;
        while(queue.length){
            // 用长度来限制每次只遍历一批
            let len = queue.length;
            cnt++;
            while(len--){
                let key = queue.shift();
                let target = map[key];
                if(target && target.length){
                    for(let k of target){
                        inDegree[k]--;
                        if(inDegree[k] == 0){
                            queue.push(k);
                        }
                    }
                }
            }
        }
        return cnt == 0 ? -1 : cnt;
    }
    //console.log(task3(3,[[1,2],[1,3],[1,1]]))

05-06笔试

第二题、表达式计算

  • 给定一个字符串形式的表达式,保证每个字符串表达式中仅包含加(+)1种运算符,计算并输出表达式结果.
  • 要注意的是,+号两边的数据仅可能包含数字字符、小数点字符与特殊字符,特殊字符包括!@#,这些特殊字符的加法运算有特别的规则:
  • !+!=0 !+@=13 !+#=4 @+@=7 @+#=20 #+#=5
  • 注意1.保证每个表达式仅包含一个运算符 2.保证表达式一定可运算且有数据结果 3.保证运算符两边数据有效(不会出现包含两个小数点之类的无效数据) 4.表达式内不存在空格 5.特殊字符的加法运算符合交换律 6.如果表达式中包含特殊字符,则运算中不会出现数字与特殊字符的加法运算 7.表达式两边的数据均不以0开头,比如不会出现这样的表达式0250+0110
  • 输入
  • 第一行: 代表字符串长度(长度在[1,1000]之间)
  • 第二行:代表一个字符串表达式
  • 输出
  • 输出一行,输出表达式结果
  • 注意: 小数最后位如果为0则省略,如结果250.010则输出250.01,结果250.0则省略为250;同时,如果计算结果为”0250”,也需以最简化形式”250”输出。

样例1输入:

输出:250.0001

       参考力扣435题,不难,慢慢做就好

第三题、魔幻森林救公主

  • 一名王子的未婚妻公主被抓到了魔幻森林中,王子需要去救她,魔幻森林危险重重,除了一些怪物之外,还有时隐时现的路障,王子只能绕过怪物、绕过出现的路障或者等路障消失之后通过。
  • 魔幻森林是一个n*n大小的二维地图,森林中的k只怪物分别在各自的位置中。每个地图点都有一个路障的状态循环,状态循环以3个单位时间作为一个环,我们用0代表没有路障,用1代表有路障,如'011'表示初始单位时间路障消失,下一个单位时间路障出现,再下一个单位时间路障继续存在.
  • 王子在每个单位时间可以向上、下、左、右某个方向移动一个地图单位,也可以选择不移动,如果王子移动方向上有怪物,或者王子移动目的地在下一个单位时间存在路漳,则不可以朝该方向移动,同时,如果王子当前位置在下一个单位时间会出现路障,那王子也不可以选择停在原地.
  • 我们需要计算王子到达公主的位置的最短时间
  • 第一行: 地图大小n (2 <=n<= 100)
  • 第二行: 怪物数量k (0 < k<= n*n-2)
  • 第三行: 怪物位置,每个位置包含rowcol用于代表rowcol例,用空格分开,位置之间用空格间隔,三个位置示例: row1 col1 row2 col2 row3 col3,地图左上角位置为0 0,输入保证所有位置合法
  • 第四行: 公主位置和王子起始位置共两个位置,row1 col1 row2 col2
  • 第五行开始的n: 每行n个字符串空格分开,每个字符串长度固定为3,内容固定只有’0‘和'1',表示每个地图点的路障的状态循环
  • 注意:
  • 1.输入数据保证一定能找到公主
  • 2.输入数据保证怪物位置与公主位置、王子起始位置不重合
  • 3.输入数据保证怪物位置、公主位置下,路障的状态循环一定为'000',即路障一定不会出现
  • 4.输入数据保证王子起始位置的路障在第一个单位时间不会出现
  • 5.输入数据保证位置一定合法
  • 输出
  • 输出一个数字,代表找到公主花费的最短时间

样例1输入

输出:5

  • 解释: 最快路王子移动顺序: (0,0)-> (0,0)-> (0,1)-> (0,2)-> (1,2)-> (2,2)
  • 另一条路 (时间6) : (0,0)->(1,0)->(1,0)-> (1,0)-> (2,0)->(2,1)->(2,2)

样例2输入

输出 4

  • 解释:最快路王子移动顺序:(0,0)->(1,0)->(0,0)-> (0,1)->(0,2)
  • 另一条路 (时间6) : (0,0)->(1,0)-> (2,0)-> (2,1)->(2,2)-> (1,2)->(0.2)
  • 思路与代码:最短路的模型,但是要注意判断怪兽和障碍物的位置,并且每个位置可以原地踏步,由于每个点的障碍物变化是以3为周期的,所以每个位置最多只需要停留3次即可。
// 5-06第三题
// 空间复杂度O(n^3) 时间复杂度最大可以是O(n^2),原本是O(V + E),顶点数+边数
// 二维矩阵的顶点数为n*n,边数为5*n^2
    const question3 = (n,k,prince,princess,obtical,map) => {
    let direction = [-1, 0, 1, 0, -1]; //遍历方向
    let res = 0;
    let grid = []; 
    for(let k = 0; k < 3; k++){
        let tempArr = [];
        for(let i = 0; i < n; i++){
            let path = [];
            for(let j = 0; j < n; j++){
                path.push(map[i][j][k]); //用三维数组存储地图
            }
            tempArr.push(path);
        }
        grid.push(tempArr);
    }
    for(let i = 0; i < k; i++){  // 将障碍加入地图中
        grid[0][obtical[i][0]][obtical[i][1]] = '1';
        grid[1][obtical[i][0]][obtical[i][1]] = '1';
        grid[2][obtical[i][0]][obtical[i][1]] = '1';
    }
    let queue = [];
    let visit = Array.from(Array(n),()=>Array(n).fill(0));
    queue.push([prince[0],prince[1],0,0]);
    // bfs最短路径问题
    while(queue.length){
        [x, y, time, wait_time] = queue.shift();
        if(x == princess[0] && y == princess[1]){
            return time;
        }
        for(let i = 0; i < 4; i++){ //往四个方向遍历
            let nx = x + direction[i];
            let ny = y + direction[i + 1]; //这里尤其注意,如果等待时间超过3,这个点已经没有意义了,直接终止
            if(nx < 0 || ny < 0 || nx >= n || ny >= n || visit[nx][ny] || grid[(time + 1) % 3][nx][ny] === '1' || wait_time > 3){
                continue;
            }
            visit[nx][ny] = 1;// 每次压入队列time + 1,等待时间为0
            queue.push([nx, ny, time + 1, 0]);
        }// 如果等待时间不超过3并且下一个坐标为0,则可以原地不动
        if(wait_time <= 3 && grid[(time + 1) % 3][x][y] === '0'){
            queue.push([x, y, time + 1, wait_time + 1]);
        }
    }
}
console.log(question3(3,1,[0,0],[0,2],[[1,1]],[['010','011','000'],['000','000','000'],['000','000','000']]));

#23届找工作求助阵地##我的实习求职记录##华为##我的求职思考##华为信息集散地#
全部评论
树上逃离如果存在多条最短路径是不是没有考虑
点赞 回复 分享
发布于 2023-09-20 14:20 浙江

相关推荐

11-04 10:30
已编辑
门头沟学院 研发工程师
开心小狗🐶:“直接说答案”
点赞 评论 收藏
分享
评论
点赞
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务