大厂笔试真题解析

文章目录

  • 2023/5/6 华为第一题:喷墨水 (模拟)
  • 2023/5/6 华为第二题:表达式计算 (模拟)
  • 2023/5/6 华为第三题:魔幻深林救公主 (BFS最短路)
  • 华为 网格最小可达跳数之和 (BFS最短路)

2023/5/6 华为第一题:喷墨水 (模拟)

大厂笔试真题解析_第1张图片
大厂笔试真题解析_第2张图片
大厂笔试真题解析_第3张图片
大厂笔试真题解析_第4张图片
模拟题,塔子哥提交ac

  • 输入处理:双字节十六进制转二进制
    十六进制转十进制再转二进制,读取多个字符串多次处理,给数组arr赋值,长度不足就数组首部即字符末尾用0填充
  • 核心逻辑:分向右,向左移动分别处理
    for循环遍历数组arr,从0开始每次向右/左移动i个位置,检查是否满足条件,满足返回此时移动的步数;
  • check函数逻辑:
    判断不移动和移动了之后,对应arr数组的下标是否为1,为1的话说明此处可以喷墨,步长step+1,最终判断step是否等于数组长度,若是返回true
  • 输出处理
    判断左/右移动标记是否为-1,若不是-1,就返回更新后的数组
package ZhenTi;

import java.sql.SQLOutput;
import java.util.Scanner;

/**
 * 5/6喷墨水
 */
public class Solution29 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();
        String[] strs = sc.nextLine().split(" ");
        int[] arr = new int[n];
        for(int i=0,c=0; i<strs.length && c<n; i++){
            //十六进制变十进制变二进制,前两位0x为前缀
            char[] bs = Integer.toBinaryString(Integer.parseUnsignedInt(strs[i].substring(2),16))
                    .toCharArray();
            //长度不足16,后边的用0填充
            for(int j=0;j<16-bs.length&&c<n;j++){
                arr[c++] = 0;
            }
            for(int j=0;j<bs.length&&c<n;j++){
                arr[c++] = bs[j]- '0';
            }
        }
//        System.out.println(arr);
        int ans,ans1=-1,ans2=-1;
        //检查向右移动,从0开始遍历,只求最短的,找到了就返回
        for(int i=0;i<n;i++){
            if(check(arr,i,0)){
                ans1 = i;
                break;
            }
        }
        //检查向左移动
        for(int i=0;i<n;i++){
            if(check(arr,i,1)){
                ans2 = i;
                break;
            }
        }
        ans = (ans1==-1?0:1) + (ans2==-1?0:1);
        System.out.println(ans);
        if(ans1!=-1){
            System.out.println("+" + ans1);
            int[] res = new int[n];
            for(int i=0;i<n;i++){
                if(arr[i]==0){
                    //输出要求堵塞的孔开启即可,因此先找到堵塞的孔处理
                    if(arr[i]==0){
                        res[i-ans1] = 1;
                    }
                }
            }
            for(int item:res){
                System.out.print(item);
            }
            System.out.println();
        }
        if(ans2!=-1){
            System.out.println("-" + ans2);
            int[] res = new int[n];
            for(int i=0;i<n;i++){
                if(arr[i]==0){
                    //输出要求堵塞的孔开启即可,因此先找到堵塞的孔处理
                    if(arr[i]==0){
                        res[i+ans2] = 1;
                    }
                }
            }
            for(int item:res){
                System.out.print(item);
            }
        }


    }
    //cnt表示位移步数,dir表示移动方向,0表示向右移动,1表示向左移动
    public static boolean check(int[] arr,int cnt,int dir){
        int ans = 0;
        int n = arr.length;
        if(dir==0){//向右移动
            for(int i=0,j;i<n;i++){
                //两种情况:不移动可以实现喷墨或者向右移动cnt位也能实现喷墨
                if(arr[i]==1 || ((j=i-cnt)>=0&&arr[j]==1 )){
                    ans++;
                }else{
                    break;
                }
            }
        }else{//向左移动
            for(int i=0,j;i<n;i++){
                //两种情况:不移动可以实现喷墨或者向左移动cnt位也能实现喷墨
                if(arr[i]==1 || ((j=i+cnt)<n&&arr[j]==1 )){
                    ans++;
                }else{
                    break;
                }
            }
        }
        return ans == n;//如果ans等于数组长度n就说明喷墨成功
    }
}

2023/5/6 华为第二题:表达式计算 (模拟)

大厂笔试真题解析_第5张图片
大厂笔试真题解析_第6张图片
大厂笔试真题解析_第7张图片
大厂笔试真题解析_第8张图片
复杂的模拟题,塔子哥提交AC
分成数字和特殊字符两部分,转换成数字相加,就不需要考虑进位的问题了
首先,遇到特殊字符就将该位换成0,并记录下特殊字符和位置,最后得到数字部分的值相加。 然后计算特殊字符相加的值,也就是题目中表达式的值乘上10的(所在位置相对小数点的位置)幂次方,比如小数点后一位就乘上10的-1幂次方。 最后转字符串处理并输出。

package ZhenTi;
/**
 * 5/6 模拟加法 华为
 */

import java.math.BigDecimal;
import java.util.*;

public class  Solution30{
    static HashMap<String,Double> sp = new HashMap<>();//特殊字符的加法原则
    static StringBuilder spl = new StringBuilder();//记录所有的特殊字符
    static BigDecimal cnt = BigDecimal.valueOf(0.0);//记录处理特殊字符后的数字
    static int count = 0;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        in.nextLine();
        String[] str = in.nextLine().split("\\+");
        String left = str[0];   //第一个数
        String right = str[1];  //第二个数
        HashMap<Integer,Integer> leftSpecial = divide(left);//个数(从0开始):索引
        HashMap<Integer,Integer> rightSpecial = divide(right);//得到cnt 用0替代特殊字符后,两个数字之和
        //加法规则
        sp.put("!+!",0.0);
        sp.put("!+@",13.0);sp.put("@+!",13.0);
        sp.put("!+#",4.0);sp.put("#+!",4.0);
        sp.put("@+@",7.0);
        sp.put("@+#",20.0);sp.put("#+@",20.0);
        sp.put("#+#",5.0);
        //处理特殊字符
        int l = spl.length() / 2;//第一个数字的特殊字符的位置和第二数字对应特殊字符位置相差len/2
        int index = 0;
        for (int i = 0; i < l; i++) {
            String temp = spl.charAt(i) + "+" + spl.charAt(l + i);

            int idx = left.indexOf('.');//判断是否有小数点
            if(idx == -1){//没有小数点, 最终结果为 sum*10^index
                index = left.length() - leftSpecial.get(i) - 1;
            }else{//有小数点,如果特殊字符在整数部分sum*10^index;小数部分,sum*10^-index
                int tem = leftSpecial.get(i);
                if(tem < idx){
                    index = idx - tem - 1;
                }else{
                    index = -(tem - idx);
                }
            }
            Double num = sp.get(temp) * Math.pow(10,index);
            String tempnum = String.valueOf(num);

            BigDecimal bigtemp = new BigDecimal(tempnum);
            cnt = cnt.add(bigtemp);//特殊字符的求和结果
        }

        //处理结果:去除后置0和小数点
        StringBuilder res = new StringBuilder(cnt.toString());
        int length = res.length();
        while(res.charAt(length -1) == '0'){
            res.deleteCharAt(length - 1);
            length--;
        }
        if(res.charAt(length - 1) == '.'){
            res.deleteCharAt(length - 1);
        }
        System.out.println(res);

    }
    //处理数字:把特殊字符变为0
    public static HashMap<Integer,Integer> divide(String str){
        int l = str.length();
        //存在小数点,返回索引;否则返回-1
        int index = str.indexOf(".");
        //保存特殊字符索引
        HashMap<Integer,Integer> Special = new HashMap<>();//count特殊字符个数-1 : i在字母中对应索引
        StringBuilder res = new StringBuilder();
        if(index == -1){         //无小数点
            for (int i = 0; i < l; i++) {  //特殊字符用0替代
                if(str.charAt(i) < '0' || str.charAt(i) > '9'){
                    Special.put(count,i);//放入哈希表
                    count++;//特殊字符统计个数+1
                    spl.append(str.charAt(i));//记录特殊字符
                    res.append('0');//用0代替
                }else{//普通字符直接添加
                    res.append(str.charAt(i));
                }
            }
        }else{           //有小数点,以小数点为间隔做相同的处理 中间加上小数点即可
            for (int i = 0; i < index; i++) {
                if(str.charAt(i) < '0' || str.charAt(i) > '9'){
                    //特殊字符;
                    Special.put(count,i);
                    count++;
                    spl.append(str.charAt(i));
                    res.append('0');
                }else{
                    res.append(str.charAt(i));
                }
            }
            res.append('.');
            for (int i = index + 1; i < l; i++) {
                //有小数点
                if(str.charAt(i) < '0' || str.charAt(i) > '9'){
                    //特殊字符;
                    Special.put(count,i);
                    count++;
                    spl.append(str.charAt(i));
                    res.append('0');
                }else{
                    res.append(str.charAt(i));
                }
            }
        }

        BigDecimal bigres = new BigDecimal(res.toString());
        cnt = cnt.add(bigres);//记录处理特殊字符后的数字,相加,得到数字1和数字2的和
        return Special;
    }
}

2023/5/6 华为第三题:魔幻深林救公主 (BFS最短路)

大厂笔试真题解析_第9张图片
大厂笔试真题解析_第10张图片
大厂笔试真题解析_第11张图片
大厂笔试真题解析_第12张图片
最短路模型
队列元素:x坐标,y坐标,时间轮次
每一个轮次 遍历四个方向 + 停留在原地

package ZhenTi;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

/**
 * 5/6华为第三题:找公主
 */
public class Solution31 {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            //大小,怪物数量
            int n = scan.nextInt(), k = scan.nextInt();
            boolean[][] traps = new boolean[n][n];//怪物位置
            for (int i = 0; i < k; i++) {
                traps[scan.nextInt()][scan.nextInt()] = true;
            }
            //公主和王子的位置
            int gx = scan.nextInt(), gy = scan.nextInt(), wx = scan.nextInt(), wy = scan.nextInt();
            String[][] strings = new String[n][];
            scan.nextLine();
            for (int i = 0; i < n; i++) {
                strings[i] = scan.nextLine().split(" ");
            }
            char[][][] grid = new char[n][n][3];//地图表格
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    grid[i][j] = strings[i][j].toCharArray();
                }
            }
            boolean[][][] vis = new boolean[n][n][3];
            int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
            Queue<int[]> queue = new ArrayDeque<>();
            queue.offer(new int[]{wx, wy, 0});//两个坐标+时间轮次
            int ans = 0;
            while (!queue.isEmpty()) {
                for (int i = queue.size(); i > 0; i--) {
                    int[] cur = queue.poll();
                    if (cur[0] == gx && cur[1] == gy) {//找到了公主
                        System.out.println(ans);
                        return;
                    }
                    int turn = (cur[2] + 1) % 3;//计算当前轮次
                    for (int[] dir : dirs) {//四个方向搜索
                        int x = cur[0] + dir[0], y = cur[1] + dir[1];
                        //边界,是否有怪物,障碍,是否访问过
                        if (x < 0 || x >= n || y < 0 || y >= n || traps[x][y] || grid[x][y][turn] == '1' || vis[x][y][turn]) continue;
                        queue.offer(new int[]{x, y, turn});
                        vis[x][y][turn] = true;
                    }
                    //可以选择停留在原地,当下一个轮次没有障碍物且未访问过
                    if (grid[cur[0]][cur[1]][turn] != '1' && !vis[cur[0]][cur[1]][turn]) {
                        queue.offer(new int[]{cur[0], cur[1], turn});
                        vis[cur[0]][cur[1]][turn] = true;
                    }
                }
                ans++;//步长
            }
            System.out.println(-1);
        }

}

华为 网格最小可达跳数之和 (BFS最短路)

大厂笔试真题解析_第13张图片

package ZhenTi;
/**
 * 网络最小可达跳数之和
 * 多源最短路径BFS
 * 参考leetcodeT417. 太平洋大西洋水流问题
 */

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Solution6 {
    static int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
    static boolean[][] visited;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        String[][] str = new String[n][n];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                str[i][j] = sc.next();
            }
        }
        visited = new boolean[n][n];
        //开始处理:从目标点反向搜索
        Queue<int[]> que = new LinkedList<>();
        int[][] nums = new int[n][n];//每个点到达终点的步数,BC默认0
        int res = 0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if (str[i][j].equals("C")){
                    que.offer(new int[]{i,j});
                }
            }
        }
        while(!que.isEmpty()){
            int[] temp = new int[2];
            temp[0] = que.peek()[0];
            temp[1] = que.poll()[1];
            for(int[] dir:dirs){
                int newX = temp[0] + dir[0];
                int newY = temp[1] + dir[1];
                if(newX<0||newY<0||newX>=n||newY>=n||visited[newX][newY]|| !str[newX][newY].equals("A")){//边界条件+访问过+非A
                    continue;
                }
                que.offer(new int[]{newX,newY});
                visited[newX][newY] = true;
                nums[newX][newY] = nums[temp[0]][temp[1]]+1;
                res += nums[newX][newY];
            }
        }
        System.out.println(res);
    }
}

你可能感兴趣的:(算法题,java,笔试真题)