牛客网 - 华为OD算法机试(可内推)

Posted code tea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客网 - 华为OD算法机试(可内推)相关的知识,希望对你有一定的参考价值。

1.前言

这几天在闭关修炼数据结构和算法, 也好几天没有更新博客了。
其实我也没学多久的算法, 满打满算牛客和leecode也就刷了四十来道题。
其实算法也没有我们一开始想象的那么难, 至少面试考的算法都还比较基础。
今天参加了华为OD的机试, 没有想象中的那么难, 但是还是熟练度的问题, 加上第一次考试有点紧张。前两题过了100%的用例, 用时一小时, 后面一个半小时都在刚第三题, 结果自己对递归的返回值处理不到位, 相当于没过吧, 晚上抽时间把代码调整了下, 应该是能正常跑过了。
现在把我经历的三道题分享出来, 有兴趣或者有建议的大佬的可以在我的博客留言。

建议看完题意后先自己思考怎么实现
本文题解只能实现功能, 并不是最优算法

ps: 一面 / 二面 也结束了, 我做了一些总结, 有兴趣可以看我这篇博客
华为od一面 / 二面复盘

第一题: 求剩余扑克牌最大顺子问题 100分

题意

扑克牌为 345678910JQKA 每种牌4张
输入是你现在的手牌, 还有已经打出去的牌

求剩下的牌中能凑出来的最大的顺子是多少
这里顺子的大小优先比较长度, 相同长度的顺子则比较牌面大小
比如:
你的手牌 3-3-3-8-8-8-8
已经打出的牌 4-4-5-5-6-6
最大的顺子是 9-10-J-Q-K-A

题解

import java.util.*;

public class Main 
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        //手牌
        String s1 = sc.nextLine();
        //出过的牌
        String s2 = sc.nextLine();

        //初始化
        HashMap<String, Integer> count = new HashMap<>(16);
        for (int i = 3; i <= 10; i++) 
            count.put(String.valueOf(i), 4);
        
        count.put("J", 4);
        count.put("Q", 4);
        count.put("K", 4);
        count.put("A", 4);

        String[] ss1 = s1.split("-");
        for (int i = 0; i < ss1.length; i++) 
            count.put(ss1[i], count.get(ss1[i]) - 1);
        
        String[] ss2 = s2.split("-");
        for (int i = 0; i < ss2.length; i++) 
            count.put(ss2[i], count.get(ss2[i]) - 1);
        


        //最大长度,队列, 读到0就输出前面的串
        String[] sa = new String[]"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A";
        Deque<String> list = new LinkedList<>();
        //从大的开始
        String result = null;
        int max = 0;
        for (int i = sa.length - 1; i >= 0; i--) 
            if (count.get(sa[i]) > 0) 
                list.offerFirst(sa[i]);
             else 
                //读到0了, 看能不能组成顺子
                if (list.size() < 5) 
                    list.clear();
                 else 
                    if (list.size() > max) 
                        max = list.size();
                        String tem = "";
                        while (list.size() > 0) 
                            tem += list.pollFirst() + "-";
                        
                        result = tem.substring(0, tem.length() - 1);
                    else
                        list.clear();
                    
                
            
        

        //读到头 处理剩余数据
        if (list.size() >= 5 && list.size() > max) 
            max = list.size();
            String tem = "";
            while (list.size() > 0) 
                tem += list.pollFirst() + "-";
            
            result = tem.substring(0, tem.length() - 1);
        

        if (max == 0) 
            System.out.println("NO-CHAIN");
         else 
            System.out.println(result);
        
    

第二题: 一系列正整数, 从中取三个数拼接后的最小数字 100分

题意

给你一系列数字, 从中取出三个数字, 如果给的数字不到三个有几个取几个
求这几个数字拼接后的最小数字是多少。

比如:
给定 18,123,22,5,12,34,23,43,344,21
拼接后的最小数字是 12,18,5的拼接, 12185

这道题比较简单, 注意边界条件的处理, 而且数字可能超长

题解

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

public class Main2 

    static BigDecimal min;

    static String[] choice = new String[3];

    public static void main(String[] args) 

        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] ss = s.split(",");

        if (ss.length == 0) 
            System.out.println(0);
            return;
         else if (ss.length == 1) 
            System.out.println(ss[0]);
            return;
         else if (ss.length == 2) 
            System.out.println(Math.min(Integer.parseInt(ss[0] + ss[1]),
                    Integer.parseInt(ss[1] + ss[0])));
            return;
        


        //数组长度为3及以上,取三个长度最短的, 相等的都取出来
        //截取0后长度最短的
        PriorityQueue<String> queue = new PriorityQueue<>(new Comparator<String>() 
            @Override
            public int compare(String o1, String o2) 
                return new BigDecimal(o1).compareTo(new BigDecimal(o2));
            
        );

        for (int i = 0; i < ss.length; i++) 
            queue.offer(ss[i]);
        

        choice[0] = queue.poll();
        choice[1] = queue.poll();
        choice[2] = queue.poll();

        //最小数字
        min = new BigDecimal(choice[0] + choice[1] + choice[2]);

        int[] ids = new int[3];
        for (int i = 0; i < 3; i++) 
            int[] idsCopy = Arrays.copyOf(ids, ids.length);
            idsCopy[i] = 1;
            build(idsCopy, 0, i, "");
        
        System.out.println(min);
    


    public static void build(int[] ids, int count, int index, String s) 
        s += choice[index];
        if (count == 2) 
            BigDecimal bigDecimal = new BigDecimal(s);
            if (bigDecimal.compareTo(min) < 0) 
                min = bigDecimal;
            
            return;
        

        for (int i = 0; i < 3; i++) 
            int[] idsCopy = Arrays.copyOf(ids, ids.length);
            if (idsCopy[i] != 1) 
                idsCopy[i] = 1;
                build(idsCopy, count + 1, i, s);
            
        
    

第三题: 两人野营, 求两人能共同到达的聚餐点数量

题意

给定一个m*n的矩阵, 矩阵中数字 0 代表空地, 可通过, 1 代表障碍, 不可通过, 数字 2 代表两个人所在的位置, 3代表聚餐点所在的位置。
求两个人同时能够到达的聚餐点有多少个?

比如:
给定, 第一行的两个数字分别是m, n
4 4
2 1 0 3
0 1 2 1
0 3 0 0
0 0 0 0
求得 2

题解

public class Main3 

    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String[] ss = s.split(" ");
        //长
        m = Integer.parseInt(ss[0]);
        //宽
        n = Integer.parseInt(ss[1]);

        List<Pos> eatPos = new ArrayList<>();
        int[][] serched = new int[m][n];

        for (int i = 0; i < m; i++) 
            for (int j = 0; j < n; j++) 
                int point = sc.nextInt();
                if (point == 3) 
                    eatPos.add(new Pos(i, j));
                
                if (point == 1) 
                    serched[i][j] = 1;
                
                arr[i][j] = point;
            
        

        if (eatPos.size() == 0) 
            System.out.println(0);
            return;
        


        for (Pos eat : eatPos) 
            //从聚餐点可以到达几个人, 如果能到达两个人, 则可达聚餐点+1
            int personFlag = 0;

            Pos left = eat.left();
            Pos right = eat.right();
            Pos up = eat.up();
            Pos down = eat.down();
            serched[eat.x][eat.y] = 1;
            //上下左右
            personFlag = search(left.x, left.y, personFlag, serched);
            if (personFlag == 2) 
                result++;
                continue;
            
            personFlag = search(right.x, right.y, personFlag, serched);
            if (personFlag == 2) 
                result++;
                continue;
            
            personFlag = search(up.x, up.y, personFlag, serched);
            if (personFlag == 2) 
                result++;
                continue;
            
            personFlag = search(down.x, down.y, personFlag, serched);
            if (personFlag == 2) 
                result++;
            
        

        System.out.println(result);
    

    static int m;
    static int n;

    static int result = 0;
    static int[][] arr = new int[99][99];

    /**
     * @param x          找的下一个点
     * @param y          找的下一个点
     * @param personFlag 记录已经找到的人数, 找到2个人就成功, 给答案+1
     * @param searched   记录已经找过的点
     */
    public static int search(int x, int y, int personFlag, int[][] searched) 
        if (!isValid(x, y, searched)) 
            return personFlag;
        
        if (arr[x][y] == 2) 
            personFlag++;
        
        if (personFlag == 2) 
            return personFlag;
        

        int[][] serchedCopy = new int[m][n];
        for (int i = 0; i < m; i++) 
            for (int j = 0; j < n; j++) 
                serchedCopy[i][j] = searched[i][j];
            
        
        serchedCopy[x][y] = 1;

        Pos current = new Pos(x, y);
        Pos left = current.left();
        Pos right = current.right();
        Pos up = current.up();
        Pos down = current.down();
        //上下左右
        personFlag = search(left.x, left.y, personFlag, serchedCopy);
        if (personFlag == 2) 
            return personFlag;
        
        personFlag = search(right.x, right.y, personFlag, serchedCopy);
        if (personFlag == 2) 
            return personFlag;
        
        personFlag = search(up.x, up.y, personFlag, serchedCopy);
        if (personFlag == 2) 
            return personFlag;
        
        personFlag = search(down.x, down.y, personFlag, serchedCopy);
        return personFlag;
    

    /**
     * 是否在边界内而且没找过
     */
    public static boolean isValid(int x, int y, int[][] searched) 
        if (x >= m || x < 0 || y >= n || y < 0) 
            return false最近更新的博客 

华为OD机试 - 自动曝光(Python) | 机试题算法思路 【2023】
华为OD机试 - 双十一(Python) | 机试题算法思路 【2023】
华为OD机试 - 删除最少字符(Python) | 机试题算法思路 【2023-02】
华为OD机试 - Excel 单元格数值统计(Python) | 机试题算法思路 【2023】
华为OD机试 -旋转骰子(Python) | 机试题算法思路 【2023】

使用说明

参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。

华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html

华为OD详细说明:

以上是关于牛客网 - 华为OD算法机试(可内推)的主要内容,如果未能解决你的问题,请参考以下文章

华为od机考在哪儿考

华为牛客网机试都是编程么

华为od机考难吗

华为OD机试 - 运动会 | 机试题算法思路 2023

华为OD机试 - 数列还原(Python) | 机试题算法思路 2023

华为OD机试 - 端口合并(Python) | 机试题算法思路 2023