美团2021春招笔试题第10场前三题

1.淘汰分数

某比赛已经进入了淘汰赛阶段,已知共有n名选手参与了此阶段比赛,他们的得分分别是a_1,a_2….a_n,小美作为比赛的裁判希望设定一个分数线m,使得所有分数大于m的选手晋级,其他人淘汰。

但是为了保护粉丝脆弱的心脏,小美希望晋级和淘汰的人数均在[x,y]之间。

显然这个m有可能是不存在的,也有可能存在多个m,如果不存在,请你输出-1,如果存在多个,请你输出符合条件的最低的分数线。

输入描述:
输入第一行仅包含三个正整数n,x,y,分别表示参赛的人数和晋级淘汰人数区间。(1<=n<=50000,1<=x,y<=n)输入第二行包含n个整数,中间用空格隔开,表示从1号选手到n号选手的成绩。(1<=|a_i|<=1000)
输出描述:
输出仅包含一个整数,如果不存在这样的m,则输出-1,否则输出符合条件的最小的值。
输入
6 2 3
1 2 3 4 5 6
输出
3

==思路:==简单理解题意,就是说给你一个区间[x,y],其实就是让总人数n通过一个数m分割开,使得m+(n-m)都在区间内,当然这个m需要是最小的m。

  • 判断是否存在:当[x,y]中两次取最大值,这个最大值小于总人数n,那么不存在,或者两次取最小值,这个最小值大于总人数m,则不存在(这种情况在写的时候忘记了)
  • 找出最小的m:这个题目最后演变为在[x,y]这个区间内选两个数i,j,使得i+j=n,同时i最小,那最简单的方法两次for循环即可。我使用的是第一次遍历i,当n-i在区间内时直接break,那么时间复杂度就为O(n)了,看题解可以使用二分查找的方式
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int length = sc.nextInt();
        int x = sc.nextInt();
        int y = sc.nextInt();
        int[] score = new int[length];
        for(int i = 0;i < length;i++){
            score[i] = sc.nextInt();
        }
        int max = y + y;
        if(max < length){	//这里少了一个判断条件
            System.out.print(-1);
        }else{
            int i;
            for(i = x;i <= y;i++){
                if(x <= length - i && length - i <= y) break;
            }
            i--;
            Arrays.sort(score);
            System.out.print(score[i]);
        }    
    }
}

2.正则序列

我们称一个长度为n的序列为正则序列,当且仅当该序列是一个由1~n组成的排列,即该序列由n个正整数组成,取值在[1,n]范围,且不存在重复的数,同时正则序列不要求排序

有一天小团得到了一个长度为n的任意序列,他需要在有限次操作内,将这个序列变成一个正则序列,每次操作他可以任选序列中的一个数字,并将该数字加一或者减一。

请问他最少用多少次操作可以把这个序列变成正则序列?

输入描述:
输入第一行仅包含一个正整数n,表示任意序列的长度。(1<=n<=20000)输入第二行包含n个整数,表示给出的序列,每个数的绝对值都小于10000。
输出描述:
输出仅包含一个整数,表示最少的操作数量。
输入
5
-1 2 3 10 100
输出
103

==思路:==主要是要明确改动最小方案的确定,如果输入序列是有序的,那么改动最好的方案就是输入序列中的i改动为正则序列中的i,这个可以通过数学归纳法进行证明

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int length = sc.nextInt();
        int[] nums = new int[length];
        for(int i = 0;i < length;i++){
            nums[i] = sc.nextInt();
        }
        Arrays.sort(nums);
        int res = 0;
        for(int i =0; i < length;i++){
            res += Math.abs((nums[i] - (i + 1)));
        }
        System.out.print(res);
    }
}

3.公司食堂

小美和小团所在公司的食堂有N张餐桌,从左到右摆成一排,每张餐桌有2张餐椅供至多2人用餐,公司职员排队进入食堂用餐。小美发现职员用餐的一个规律并告诉小团:当男职员进入食堂时,他会优先选择已经坐有1人的餐桌用餐,只有当每张餐桌要么空着要么坐满2人时,他才会考虑空着的餐桌;

当女职员进入食堂时,她会优先选择未坐人的餐桌用餐,只有当每张餐桌都坐有至少1人时,她才会考虑已经坐有1人的餐桌;

无论男女,当有多张餐桌供职员选择时,他会选择最靠左的餐桌用餐。现在食堂内已有若干人在用餐,另外M个人正排队进入食堂,小团会根据小美告诉他的规律预测排队的每个人分别会坐哪张餐桌。

输入描述:
第一行输入一个整数T(1<=T<=10),表示数据组数。每组数据占四行,第一行输入一个整数N(1<=N<=500000);第二行输入一个长度为N且仅包含数字0、1、2的字符串,第i个数字表示左起第i张餐桌已坐有的用餐人数;第三行输入一个整数M(1<=M<=2N且保证排队的每个人进入食堂时都有可供选择的餐桌);第四行输入一个长度为M且仅包含字母M、F的字符串,若第i个字母为M,则排在第i的人为男性,否则其为女性
输出描述:
每组数据输出占M行,第i行输出一个整数j(1<=j<=N),表示排在第i的人将选择左起第j张餐桌用餐。
输入
1
5
01102
6
MFMMFF
输出
2
1
1
3
4
4

==思路:==最简单的思路,直接超时。遍历性别数组,然后遍历table数组,时间复杂度是O(n2),不出意外是会超时的。看题解的思路:使用优先队列,分别建立三个优先队列,存放人数为0,1,2的桌子,因为使用的是优先队列,所以每次出队的时候都是选择当前最小元素,那么就对应着从左到右选择

对于M来说,有以下情况:

  • 人数为1的优先队列不为空,则该桌子下标弹出队,加入到人数为2的队列里
  • 人数为1的优先队列为空,则选择人数为0的桌子下标出队,加入到人数为1的队列里

对于F来说,情况一样,此题还需要注意的是不能使用Scanner做输入输出,这样会超时

优先队列:每次出队的是都是当前队里最小(最大)的元素,因为内部使用的是堆实现,所以出队的时间复杂度为O(logn)

//我的错误思路
import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        int count = Integer.parseInt(reader.readLine());
        while(--count >= 0){
            int length = Integer.parseInt(reader.readLine());
            String s = reader.readLine();
            char[] r = s.toCharArray();
            int[] co = new int[r.length];
            for(int i = 0;i < r.length;i++){
                co[i] = Integer.valueOf(r[i]) - 48;
            }

            int nums = Integer.parseInt(reader.readLine());
            String sex = reader.readLine();
            char[] csex = sex.toCharArray();
            int[] res = new int[csex.length];
            for(int j = 0;j < csex.length;j++){
                if(csex[j] == 'M'){
                    
                    int flag = 0;
                    int flag2 = 0;
                    int empty = 0;
                    for(int i = 0; i < co.length;i++){
                        if(flag2 == 0 && co[i] == 0){
                            empty = i;
                            flag2 = 1;
                        }
                        if(co[i] == 1){
                            co[i]++;
                            res[j] = i;
                            flag = 1;
                            break;
                        }

                    }
                    if(flag == 0){
                        res[j] = empty;
                        co[empty]++;
                   }
                }else{
                    int flag = 0;
                    int flag2 = 0;
                    int empty = 0;
                    for(int i = 0;i < co.length;i++){
                        if(co[i] == 0){
                            co[i]++;
                            res[j] = i;
                            flag = 1;
                             break;
                        }
                        if(flag2 == 0 && co[i] == 1){
                            empty = i;
                            flag2 = 1;
                        }
                    }
                    if(flag == 0){
                        res[j] = empty;
                        co[empty]++;
                   }
                }
           }
            for(int i = 0;i < res.length;i++){
                writer.write(Integer.toString(res[i] + 1));
                writer.newLine();
            }
            writer.flush();
        }
    }
}

使用优先队列的题解

import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        int count = Integer.parseInt(reader.readLine());
        while(--count >= 0){
            int tableLength = Integer.parseInt(reader.readLine());
            String table = reader.readLine();
            int[] tables = new int[tableLength];
            for(int i = 0;i < tableLength;i++){
                tables[i] = table.charAt(i) - '0';
            }
            int peopleLength = Integer.parseInt(reader.readLine());
            String people = reader.readLine();
            
            List<PriorityQueue<Integer>> pqs = new ArrayList<>();
            pqs.add(new PriorityQueue<Integer>());
            pqs.add(new PriorityQueue<Integer>());
            pqs.add(new PriorityQueue<Integer>());
            for(int i = 0;i < tableLength;i++){
                pqs.get(tables[i]).add(i);
            }
            int[] res = new int[peopleLength];
            for(int i = 0;i < peopleLength;i++){
                int index;
                if(people.charAt(i) == 'M'){
                    if(!pqs.get(1).isEmpty()){
                        index = pqs.get(1).poll();
                        pqs.get(2).add(index);
                        res[i] = index;
                    }else{
                        index = pqs.get(0).poll();
                        pqs.get(1).add(index);
                        res[i] = index;
                    }
                }else{
                    if(!pqs.get(0).isEmpty()){
                        index = pqs.get(0).poll();
                        pqs.get(1).add(index);
                        res[i] = index;
                    }else{
                        index = pqs.get(1).poll();
                        pqs.get(2).add(index);
                        res[i] = index;
                    }
                }
                
            }
            for(int j = 0;j < peopleLength;j++){
                writer.write(Integer.toString(res[j] + 1));
                writer.newLine();
            }
            writer.flush();
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值