2020-4-16-美团笔试

5道算法题,俩小时

1、奖学金人数

n个学生,m个科目。已知每个学生的分数。给学生发单科奖学金,取每科最高分的同学(可能并列,都发)发奖学金。问一共有多少同学得到了奖学金?

分析

  • 这个全通过了,思路比较简单,统计每科最高分,给分数为最高的同学发奖。
  public static int meituan1(){
        Scanner sc = new Scanner(System.in);
        //学生人数
        int n = sc.nextInt();
        //考试科目数
        int m = sc.nextInt();
        int [][] score = new  int [n][m];
        //第i学生
        for (int i = 0; i < score.length; i++) {
            //第j科目
            for (int j = 0; j < score[i].length; j++) {
                score[i][j] = sc.nextInt();
            }
        }
        //记录学生是否是最好
        boolean best [] = new boolean[n];
        //查看每一科 最好的
        for (int j = 0; j < m; j++) {
            int bestScore = 0;
            //每一个学生
            for(int i = 0; i <n;i++){
                if(score[i][j] > bestScore){
                    bestScore = score[i][j];
                }
            }
            for(int i = 0;i <n ;i++){
                if(score[i][j] == bestScore){
                    best[i] = true;
                }
            }
        }
        int sum = 0;
        for (int i = 0; i < best.length; i++) {
            if(best[i]){
                sum++;
            }
        }
        System.out.println();
        return  sum;
    }

2、最小循环节

给定 a b m x 按照公式迭代计算 x=(a*x+b)%m;
x会产生循环序列,问最小的循环序列长度。

分析

  • 感觉思路不太对,只过了一半的测试
  • 用map,每一个x值,作为key。
 public static void meituan2(){
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int m = sc.nextInt();
        int x= sc.nextInt();
        HashMap<Integer,Integer> map = new HashMap<>();
        while (true){
            x=(a*x+b)%m;
            if (map.containsKey(x)){
                map.put(x,map.get(x)+1);
            }else{
                map.put(x,1);
            }
            if(map.get(x) >2){break;}
        }
        System.out.println(map.size());
    }

3、第k小的坐标

a1 = (x1,y1)与a2=(x2,y2)比较。
x1>x2 则 a1 >a2
x1 < x2 则 a1 < a2
如果x1 == x2,比较y,给出结论。
给出n个数,(x,y)都可以取n中的任意一个数,求第k小坐标。

分析

  • 想出了一个比较智障的算法,通过了一半的样子,提示是超时。。。。。。。
  • 生成所有的坐标,按规则排序,找出第k小。
  • 隐隐约约感觉不对,是不是有更简单的法子。事后诸葛亮想了想,还真是有。先将输入的n个数排序,用两层循环,分别对x,y取值,因为是排序好的,循环取数时候,坐标也是递增的,计数到k就行了。。。。。。。。。。。

不太行的写法

public static void meituan3(){
        ArrayList<Pair> list = new ArrayList<>();

        Scanner sc = new Scanner(System.in);
        //多少个数
        int nums = sc.nextInt();
        //第k小
        int k = sc.nextInt();
        int data [] = new int [nums];
        for (int i = 0; i < data.length; i++) {
            data[i] = sc.nextInt();
        }
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data.length; j++) {
                list.add(new Pair(data[i],data[j]));
            }
        }
        list.sort(new Comparator<Pair>() {
            @Override
            public int compare(Pair p1, Pair p2) {              
                if(p1.x > p2.x){
                    return 1;
                }else if(p1.x < p2.x){
                    return -1;
                }else{
                    // ==
                    if(p1.y > p2.y){
                        return 1;
                    }else if(p1.y < p2.y){
                        return -1;
                    }else{
                        return 0;
                    }
                }
            }
        });
        System.out.println(list.get(k-1));
    }

事后诸葛亮法

public static void meituan3Improve(){      
        Scanner sc = new Scanner(System.in);
        //多少个数
        int nums = sc.nextInt();
        //第k小
        int k = sc.nextInt();
        int data [] = new int [nums];       
        for (int i = 0; i < data.length; i++) {
            data[i] = sc.nextInt();
        }
        Arrays.sort(data);
        int count = 0;
        int x= 0;
        int y = 0;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data.length; j++) {
                count++;
                if(count == k){
                    x= i;
                    y = j;
                    break;
                }                
            }
        }       
        System.out.println("("+x+","+y+")");
    }

4、伪中位数

给出n,k。n代表后续有n个数,参与排序。这n个数定义中位数,对于排序好的数组,i=(1+n)/2 并向下取整,第i个数就是伪中位数。
k表示数组中的一个数。
想让在该数组中为k的数成为伪中位数,在数组应该至少要插入多少元素?
如 4 2
2 3 3 3
一共四个数 想让2成为中位数,要在2之前插入比2小的数1 1,2就是中位数了。此时返回2,因为插入了两个1。

分析

  • 经过验证,伪中位数,就是如果n是奇数,就是正中央的数,如果是偶数个数,就是左半边最后一个数。
  • 将数组排序,计算中位数所在的下标mid。
  • 找出k所在下标j。
  • 如果两下标相等,不用插入元素。
  • 如果j < mid。说明j左边需要插入元素。计算j右边的元素个数,n-1-j,计算j左边元素个数 j。右边比左边多的元素,如果插入元素,使j左右元素个数相等,j就处在中位数位置,但是少插入一个也可以,就是总数是偶数的情况。所以n -1-j-j - 1;
  • 反之,j>mid。j - (n-1-j) -1;
  • 但是很失望,也是没有全部通过!!!!!
 public static void meituan4(){

        Scanner sc = new Scanner(System.in);
        //多少个数
        int n = sc.nextInt();
        int data [] = new int [n];
        //目标数 使k成为中位数
        int k = sc.nextInt();
        for (int i = 0; i < data.length; i++) {
            data[i] = sc.nextInt();
        }
        Arrays.sort(data);
        //j 是k所在位置
        int j = 0;
        for (j = 0; j < data.length; j++) {
            if(data[j] == k){
                break;
            }
        }
       int mid = getMidPos(data);
        int res = 0;
        if(mid == j){
           res = 0;
        }else if(j < mid){
            // n-1-j j右边有几个 j就是j左边有几个 j左右边数目相同 还要减1
            res = n -1-j-j - 1;
        }else{
            res =  j - (n-1-j) -1;
        }
        System.out.println(res);

    }

5、没来及做

在这里插入图片描述

发布了72 篇原创文章 · 获赞 0 · 访问量 712

猜你喜欢

转载自blog.csdn.net/weixin_40300702/article/details/105569684