华为OD机试题(不间断更新)

Posted Mr. Dreamer Z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了华为OD机试题(不间断更新)相关的知识,希望对你有一定的参考价值。

目录

第一题:字符串消消乐

第二题,We Are A Team

第三题 求剩余扑克牌最大顺子问题

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


这些代码都未进行优化,只是为了记录对应题目以及做个总结,是基于思路去写的。有更好方式的童鞋请告知,后续会抽出时间进行代码优化

第一题:字符串消消乐

字符串消消乐。相邻且相同的字符串可以消除,消除后字符继续消除,给你一串字符,给出最终的长度。字符串大小写敏感,有其他非字母字符返回0。

例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。
之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

这道题其实比较简单了,我们只需要判断相邻的两个字符是否是一致的。如果一致,那么将其排除掉,重新组装字符串。如果不一致,那么下标往后移动

public static void main(String[] args) 
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) 
            String str = scanner.nextLine();
            String str1 = str.replaceAll("[^a-zA-Z]", "");
            if (str1.length() != str.length()) 
                System.out.println(0);
            
            System.out.println(getVal(str, 0));
        
    

    private static String getVal(String str, int i) 
        // 如果i==str.length
        if (i == str.length() - 1 || "".equals(str)) 
            return str;
        
        
        if (str.charAt(i) == str.charAt(i + 1)) 
            // 如果相同,那么直接消除
            String sub1 = str.substring(0, i);
            String sub2 = str.substring(i + 1 + 1);
            str = sub1 + sub2;
            // 从头开始
            i = 0;
         else 
            // i+1继续寻找
            i = i + 1;
        
        return getVal(str, i);
    

这道题的关键点在于,避免处理非字符的数据以及如何组装字符串,还有如果消除相同字符之后,下标从头开始。

第二题,We Are A Team

【We Are A Team】

总共有 n 个人在机房,每个人有一个标号(1<=标号<=n),他们分成了多个团队,需要你根据收到的 m 条消息判定指定的两个人是否在一个团队中,具体的:

1、消息构成为 a b c,整数 a、b 分别代表两个人的标号,整数 c 代表指令

2、c == 0 代表 a 和 b 在一个团队内

3、c == 1 代表需要判定 a 和 b 的关系,如果 a 和 b 是一个团队,输出一行’we are a team’,如果不是,输出一行’we are not a team’

4、c 为其他值,或当前行 a 或 b 超出 1~n 的范围,输出‘da pian zi’

输入描述

第一行包含两个整数 n,m(1<=n,m<100000),分别表示有 n 个人和 m 条消息
随后的 m 行,每行一条消息,消息格式为:a b c(1<=a,b<=n,0<=c<=1)
输出描述: 1、c ==1,根据 a 和 b 是否在一个团队中输出一行字符串,在一个团队中输出‘we are a team’,不在一个团队中输出’we are not a team’ 2、c 为其他值,或当前行 a 或 b 的标号小于 1 或者大于 n 时,输出字符串‘da pian zi’
如果第一行 n 和 m 的值超出约定的范围时,输出字符串”Null”。
示例1 输入输出示例仅供调试,后台判题数据一般不包含示例

输入

5 7

1 2 0

4 5 0

2 3 0

1 2 1

2 3 1

4 5 1

1 5 1

输出

We are a team

We are a team

We are a team

We are not a team

示例2 输入输出示例仅供调试,后台判题数据一般不包含示例

输入

5 6

1 2 0

1 2 1

1 5 0

2 3 1

2 5 1

1 3 2

输出

we are a team

we are not a team

we are a team

da pian zi

说实话,我最讨厌这种描述臭又长,得花大量时间去审题,找规则,试错的题。特别是在考试的时候~

这道题其实也还好,我们首先要弄清楚a,b,c这三个的含义,a和b代表人员标号,c代表是否在一个团队。而且这道题首先会由输入告知你一部分所属一个团队的人员。

我们可以创建两个集合,一个集合来收集所属同一团队的人员信息,第二个集合来收集我们需要去输出的人员信息。但是这其中有一个难点,就是说我们要根据给出的信息去推演出所属一个团队的人员。比如说:1 2 0 、2 3 0 ,那么我们则可以得知,1和3是在同一个团队中。那么将其算出,加入我们的第一个集合中。或者1 2 0 和 1 5 0,那么我们也要得出2和5是所属与同一个团队中。

public class Test05 

    public static void main(String[] args) 
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) 
            int n = scanner.nextInt();
            int m = scanner.nextInt();
            // 输入
            List<Team> list = new ArrayList<>();
            List<Team> sendList = new ArrayList<>();
            for (int i = 0; i < m; i++) 
                int a = scanner.nextInt();
                int b = scanner.nextInt();
                int c = scanner.nextInt();
                if (c == 0) 
                    list.add(new Team(a, b, c));
                 else 
                    sendList.add(new Team(a, b, c));
                
            
            List<Team> teamList = getList(list);
            for (Team team : sendList) 
                if ((team.c != 0 && team.c != 1) || Math.min(team.a, team.b) < 1 || Math.max(team.a, team.b) > n) 
                    System.out.println("da pian zi");
                    continue;
                

                if (team.c == 1) 
                    // 判断是否在之前的集合中存在
                    List<Team> collect = teamList.stream().filter(val -> val.getA() == team.a && val.getB() == team.b).collect(Collectors.toList());
                    if (collect != null && collect.size() > 0) 
                        System.out.println("we are a team");
                     else 
                        System.out.println("we are not a team");
                    
                
            
        
    

    private static List<Team> getList(List<Team> list) 
        // 当加入数据时,需要判断1,2  2,3 -> 1,3 这种推演
        List<Team> newList = new ArrayList<>();
        for (int i = 0; i < list.size() - 1; i++) 
            for (int j = i + 1; j < list.size(); j++) 
                Team team1 = list.get(i);
                Team team2 = list.get(j);
                // 由于都是0,那么代表是一个团队
                if (team1.b == team2.a) 
                    // 那么将team1.a 和 team2.b进行组合
                    newList.add(new Team(team1.a, team2.b, 0));
                 else if (team1.a == team2.a) 
                    newList.add(new Team(team1.b, team2.b, 0));
                 else if (team1.a == team2.b) 
                    newList.add(new Team(team1.b, team2.a, 0));
                
            
        
        // 将两个集合组装
        list.addAll(newList);
        return list;
    



class Team 
    int a;
    int b;
    int c;

    public int getA() 
        return a;
    

    public int getB() 
        return b;
    

    public Team(int a, int b, int c) 
        this.a = a;
        this.b = b;
        this.c = c;
    

这道题的关键点:1.审题(去理解清楚这种臭又长描述的题的具体信息,一般来说这种题都比较简单,如果理解清楚容易做出来) 2.需要自己去推演出处于同一个团队的人员

第三题 求剩余扑克牌最大顺子问题

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

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

 

这道题和牛客网华为算法题HJ88差不多,是同类型题。

首先审题,由题可知,有3-A每种4张牌,我们手里有牌,打出去有牌,剩下的还有牌

输入时,我们就可以得知手中牌和打出去的牌。

第一步,我们先将所有的牌得到。

第二步,将手中的牌和打出去的牌过滤掉

第三步,遍历所有的牌,开始组合,如果遇到还剩0张牌的牌,那么保存当前组合的数据,跳过当前牌,往下继续组合

 public static void main(String[] args) 
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) 
            // 手牌
            String str1 = scanner.nextLine();
            // 打出的牌
            String str2 = scanner.nextLine();

            // 先得到总的牌
            LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
            for (int i = 3; i <= 10; i++) 
                linkedHashMap.put(i + "", 4);
            
            linkedHashMap.put("J", 4);
            linkedHashMap.put("Q", 4);
            linkedHashMap.put("K", 4);
            linkedHashMap.put("A", 4);

            // 将剩下的牌得到
            String[] arr1 = str1.split("-");
            for (int i = 0; i < arr1.length; i++) 
                String key = arr1[i];
                linkedHashMap.put(key, linkedHashMap.get(key) - 1);
            

            String[] arr2 = str2.split("-");
            for (int i = 0; i < arr2.length; i++) 
                String key = arr2[i];
                linkedHashMap.put(key, linkedHashMap.get(key) - 1);
            

            // 得到剩下的牌
            Set<String> keySet = linkedHashMap.keySet();
            List<String> list = getList(keySet, linkedHashMap);
            // 得到最长的,如果有相同的,那么取下一个
            int max = 0;
            String res = "";
            for (String str : list) 
                String[] subArr = str.split("-");
                if (subArr.length >= max) 
                    max = subArr.length;
                    res = str;
                
            
            System.out.println(res);
        
    

    private static List<String> getList(Set<String> keySet, LinkedHashMap<String, Integer> linkedHashMap) 
        String res = "";
        List<String> list = new ArrayList<>();
        int idx = 0;
        boolean flag = false;
        for (String key : keySet) 
            idx++;
            if (linkedHashMap.get(key) <= 0) 
                if (idx == keySet.size()) 
                    // 如果是最后一位,那么说明都已经放入集合中
                    flag = true;
                

                if(!"".equals(res))
                    // 如果遇到是val是0的key,那么自动组装放入集合
                    list.add(res.substring(0, res.length() - 1));
                    // 重新赋值
                    res = new String();
                
                continue;
             else 
                res += key + "-";
            

            // 如果flag为false,那么说明最后一位未放入集合中
            if (idx == keySet.size() && !flag) 
                list.add(res.substring(0, res.length() - 1));
            
        
        return list;
    

这道题的难点其实就是如何组装数据,组装数据我们需要注意一下几点:

1.如何遇到该类牌的数量为0,那么将其之前的组合记录,然后跳过当前类型牌

2.头尾牌为0时,需要特殊处理。如果头牌0,注意下标问题。如果尾牌不是0,那么需要将当次组装的数据全部放入集合中

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

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

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

这道题比较简单,我们只需要考虑当前给定的数字是否大于3个以及找出最小的三个进行组装即可

public static void main(String[] args) 
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) 
            String str = scanner.nextLine();
            String[] numArr = str.split(",");
            int[] arr = new int[numArr.length];
            for (int i = 0; i < numArr.length; i++) 
                arr[i] = Integer.valueOf(numArr[i]);
            
            Arrays.sort(arr);
            List<Integer> list = new ArrayList<>();
            if (numArr.length < 3) 
                for (int i = 0; i < arr.length; i++) 
                    list.add(arr[i]);
                
             else 
                for (int i = 0; i < 3; i++) 
                    list.add(arr[i]);
                
            

            // 组合起来之后求最小值
            String[] s = new String[list.size()];
            for (int i = 0; i < list.size(); i++) 
                s[i] = list.get(i) + "";
            
            Arrays.sort(s, ((o1, o2) -> (o1 + o2).compareTo(o2 + o1)));

            StringBuilder sb = new StringBuilder();
            for (String st : s) 
                sb.append(st);
            
            System.out.println(sb);
        
    

关键点就是如何找到最小的组合,通过compareTo()进行组合得到最下的组合数据

以上是关于华为OD机试题(不间断更新)的主要内容,如果未能解决你的问题,请参考以下文章

华为OD机试题 - 最近的点(JavaScript)| 含思路

华为OD机试题 - 最小叶子节点(JavaScript)| 含思路

华为OD机试题 - 寻找路径(JavaScript)| 机考必刷

华为OD机试题 - 不等式(JavaScript)| 含思路

华为OD机试题 - TLV 编码(JavaScript)| 含思路

华为OD机试题 - 对称美学(JavaScript)| 机考必刷