美团点评2019春招后台开发方向笔试算法题第一题:黑白矩阵

分享一下我的代码,顺便希望大家帮忙看看还有没有问题。也可以到我的博客查看这篇文章,包含题目描述:https://52heartz.top/articles/algorithm-black-white-matrix/

思路

把矩阵看作像国际象棋棋盘一样的黑白矩阵。最终的目的就是要黑格子中的数字相同,白格子中的数字相同。同时我们希望用最少的修改次数使矩阵变成这种状态。

分别统计黑格子和白格子中出现最多的数字和第二多的数字以及出现的次数。

如果黑格子中出现最多的数字和白格子中出现最多的数字不一样,那么只需要分别把黑白格子中除了出现最多的数字以外的其他数字改为和出现最多的数字相同。就可以达到满足题意的状态,而且这种方法修改的次数是最少的。再具体一点就是使用矩阵的大小减去黑白格子中出现最多的数字的个数,也就是减去不需要修改的数,剩下的就是需要修改的数字的个数。

如果黑格子中出现最多的数字和白格子中出现最多的数字一样。那么就要考虑出现第二多的数字了。那么这个时候可能有两种组合,

组合1:黑格子中出现最多的数字的个数和白格子中出现第二多的数字的个数相加

组合2:白格子中出现最多的数字的个数和黑格子中出现第二多的数字的个数相加

这个组合的数就是不需要修改的数的个数,哪个组合的数更大,就说明这个组合需要修改的数更少。所以用矩阵的大小减去更大的组合数,就是最少需要修改的次数。

代码

代码不是当时用于提交的代码,把输入流绑定到了文件输入流方便本地测试,大家也可以使用后边的测试用例测试一下。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        File file = new File("test_case_1.txt");
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            System.setIn(fileInputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Scanner sc = new Scanner(System.in);
        while (sc.hasNextInt()) {
            HashMap<Integer, Integer> blackCounterMap = new HashMap<>();
            HashMap<Integer, Integer> whiteCounterMap = new HashMap<>();

            int columns = sc.nextInt();
            int rows = sc.nextInt();
            int elementNum = rows * columns;

            int inputTemp = 0;
            for (int i = 0; i < rows; ++i) {
                for (int j = 0; j < columns; ++j) {
                    inputTemp = sc.nextInt();
                    // i + j为偶数看作黑格子,i + j为奇数,看作白格子
                    if (((i + j) & 1) == 0) {
                        if (blackCounterMap.containsKey(inputTemp)) {
                            blackCounterMap.put(inputTemp, blackCounterMap.get(inputTemp) + 1);
                        } else {
                            blackCounterMap.put(inputTemp, 1);
                        }
                    } else {
                        if (whiteCounterMap.containsKey(inputTemp)) {
                            whiteCounterMap.put(inputTemp, whiteCounterMap.get(inputTemp) + 1);
                        } else {
                            whiteCounterMap.put(inputTemp, 1);
                        }
                    }
                }
            }

            // 第一个下标区分元素出现次数最多和第二多,0代表最多,1代表第二多
            // 第二个下标区分 key 和 value,0代表key,1代表value
            // blackMax[0][0] 黑格子中出现次数最多的元素
            // blackMax[0][1] 黑格子中出现次数最多的元素出现的次数
            // blackMax[1][0] 黑格子中出现次数第二多的元素
            // blackMax[1][1] 黑格子中出现次数第二多的元素出现的次数
            // whiteMax数组和blackMax数组类似
            int[][] blackMax = new int[2][2];
            int[][] whiteMax = new int[2][2];

            findMaxAndSecondMax(blackCounterMap, blackMax);
            findMaxAndSecondMax(whiteCounterMap, whiteMax);

            // 如果黑格子中出现次数最多的和白格子中出现最多的数字不一样,那么就
            // 用元素总数减去这两个数,把不是出现最多的数字改为相应的数字即可
            int result = 0;
            if (blackMax[0][0] != whiteMax[0][0]) {
                result = elementNum - blackMax[0][1] - whiteMax[0][1];
            } else {
                int combination1 = blackMax[0][1] + whiteMax[1][1];
                int combination2 = blackMax[1][1] + whiteMax[0][1];
                if (combination1 > combination2) {
                    result = elementNum - combination1;
                } else {
                    result = elementNum - combination2;
                }
            }
            System.out.println(result);
        }
    }

    /**
     * 从countermap中找出出现次数最多和第二多的数和出现的次数,存到max数组中
     * @param countermap
     * @param max
     */
    private static void findMaxAndSecondMax(HashMap<Integer, Integer> countermap, int[][] max) {
        for (Map.Entry<Integer, Integer> entry : countermap.entrySet()) {
            int maxTemp = entry.getValue();
            if (maxTemp > max[0][1]) {
                max[1][0] = max[0][0];
                max[1][1] = max[0][1];
                max[0][0] = entry.getKey();
                max[0][1] = maxTemp;
            } else if (maxTemp > max[1][1]) {
                max[1][0] = entry.getKey();
                max[1][1] = maxTemp;
            }
        }
    }
}

测试用例

3 3
1 1 1
1 1 1
1 1 1

3 3
1 1 1
1 5 1
1 1 1

4 4
1 2 1 2
2 1 2 1
1 2 1 2
2 1 2 1

4 4
1 2 3 4
2 1 4 3
1 2 3 4
2 1 4 3

4 4
1 2 3 3
2 1 3 3
1 2 3 3
2 1 3 3

4 4
1 5 3 3
2 6 3 3
8 2 3 3
2 7 3 3
对于这几个测试用例,我的程序的运行结果是
4
4
0
8
8
9

#美团##春招##笔试题目##笔经#
全部评论

相关推荐

写面经&nbsp;攒人品!!!自我介绍然后对照项目问了一些细节,不过项目部分我做的开发工作比较少,所以感觉没有让他比较满意的技术点。看我项目里涉及到了MySQL就简单写了一个MySQL的查询语句,大概是从两个表里查询成绩排名前5的学生,不过好像忘记在排序的时候进行倒序了(小哭一下)。问了简单的基础知识:1、Java的关键字有哪些;2、static关键字的作用是什么;3、Java中的同步和异步(哈哈想到线程哪里去了,没答上来,大哭一下呜呜);4、http和https的区别;5、Linux的常用命令(Windows下查看ip的命令hh不会);6、还有一些什么不太记得了。开放性问答:1、在学校里的校园经历中最有成就感的事情是什么;2、就业指导会的作用是什么;3、测试用户点奶茶外卖过程。(这里当时忘记考虑到使用红包方面的问题了);4、交给你一个任务的时候你会怎么做。代码题:给你10个推荐卡片,判断是否按推荐相关指数递减的顺序进行展示的。写完之后自己设置测试用例去测一下这个代码(嗯,有点问题hh)。反问:问了部门的业务;问了哪些地方还应该提升。答:测试思维可以再发散一些,总结能力再突出一些。面试官小姐姐人很温柔滴,整个过程感觉也很亲切,可能自己还是太菜了目前还在泡池子希望给个机会吧,我在继续努力了呢!!!——————————————————————更新:家人们!给二面了!
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务