【美团2021校招编程题】

【美团2021校招编程题】

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 - stack.size()也处于[x, y]之间
  • 第一个满足条件的成绩则为最低分数线,将其弹出

代码实现:

import java.io.*;
import java.util.*;

/**
 * @author Jeremy Li
 * @data 2021/2/7 - 12:22
 */
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] condition = br.readLine().trim().split(" ");
        int n = Integer.parseInt(condition[0]);
        int x = Integer.parseInt(condition[1]);
        int y = Integer.parseInt(condition[2]);
        int[] score = new int[n];
        String[] scores = br.readLine().trim().split(" ");
        for (int i = 0; i < n; i++) {
            score[i] = Integer.parseInt(scores[i]);
        }
        bw.write(Integer.toString(solution(n, x, y, score)));
        br.close();
        bw.close();
    }

    public static int solution(int n, int x, int y, int[] score) {
        // 将成绩进行排序
        Arrays.sort(score);
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            stack.push(score[i]);
            // 让淘汰和晋级的人数都在[x,y]区间之内
            if ((stack.size() >= x && stack.size() <= y) && (n - stack.size() >= x && n - stack.size() <= y)){
                break;
            }
        }
        // 根据stack的size判断是跳出循环还是循环结束
        if (stack.size() != n) return stack.pop();
        return -1;
    }

}

2、正则序列

题目描述:

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

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

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

输入描述:
    输入第一行仅包含一个正整数n,表示任意序列的长度。(1<=n<=20000)
    输入第二行包含n个整数,表示给出的序列,每个数的绝对值都小于10000。

输出描述:
	输出仅包含一个整数,表示最少的操作数量。

输入例子1:
    5
    -1 2 3 10 100
输出例子1:
    103

思路分析:

1、要想实现最少的操作次数,则将每个位置的数字通过操作得到正则序列中该位置所对应数字,此时操作次数最少

代码实现:

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int n = Integer.parseInt(br.readLine().trim());
        String[] arr = br.readLine().trim().split(" ");
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[i] = Integer.parseInt(arr[i]);
        }
        int count = getCount(n, res);
        bw.write(String.valueOf(count));
        br.close();
        bw.close();
    }

    public static int getCount(int n, int[] res) {
        Arrays.sort(res);
        int count = 0;
        // 这里从1开始,因为正则序列也是从1开始的,i可以表示正则序列中该位置的值
        for (int i = 1; i <= n; i++) {
            // 输入数组中同位置的数与正则序列中对应的数相减取绝对值,即为进行操作的次数
            count += Math.abs(res[i - 1] - i);
        }
        return count;
    }
}

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:
1
5
01102
6
MFMMFF

输出例子1:
2
1
1
3
4
4

思路分析:

1、桌子有三种状态:空桌、有一人、有两人(满),每种状态有一定数量的桌子,则可以考虑用list或者stack存放这三种状态的桌子,每个位置可以存放一个队列。这里为什么选择队列来存放桌子索引?因为题中规定无论男女,当有多张餐桌供职员选择时,他会选择最靠左的餐桌用餐,则利用队列的FIFO特性存放桌子索引

2、依次判断进入员工的性别,若为男性,则首先判断单人桌是否有空余,即list或stack中索引为1的位置存放的队列是否为空,若为空,则从左起找空桌(将容器中索引为0存放的队列的元素弹出,并加入索引为1的队列中),若不为空,则选择该桌,并加入索引为2的队列中。女性同理。

3、将每个员工的选择存入数组中,返回数组。

代码实现:

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    // 数组组号
    int T = Integer.parseInt(br.readLine());

    for (int i = 0; i < T; i++) {
        // 桌子的个数
        int N = Integer.parseInt(br.readLine());
        // 每张桌子的状态
        String tables = br.readLine();
        // 此时剩余座位可容纳的人数
        int M = Integer.parseInt(br.readLine());
        // 进入餐厅的员工性别
        String enters = br.readLine();
        int[] res = solution(tables, enters);
        for (int r : res) {
            bw.write(Integer.toString(r));
            bw.newLine();
        }
    }
    br.close();
    bw.close();
}

public static int[] solution(String tables, String enters) {
    Stack<PriorityQueue<Integer>> stack = new Stack<>();
    // 初始化stack
    stack.add(new PriorityQueue<>());
    stack.add(new PriorityQueue<>());
    stack.add(new PriorityQueue<>());
    // 从左到右依次将每个桌子的索引存到对应状态的位置
    for (int i = 0; i < tables.length(); i++) {
        stack.get(tables.charAt(i) - '0').add(i + 1);
    }
    int[] res = new int[enters.length()];
    // 员工开始进入
    for (int i = 0; i < enters.length(); i++) {
        // 每个员工的选择
        int choose;
        if (enters.charAt(i) == 'M'){
            // 当没有单人桌时
            if (stack.get(1).isEmpty()){
                choose = stack.get(0).poll();
                stack.get(1).add(choose);
            }else {
                // 当有单人桌时
                choose = stack.get(1).poll();
                stack.get(2).add(choose);
            }
        }else {
            if (stack.get(0).isEmpty()){
                choose = stack.get(1).poll();
                stack.get(2).add(choose);
            }else {
                choose = stack.get(0).poll();
                stack.get(1).add(choose);
            }
        }
        res[i] = choose;
    }
    // 这里我最初是直接用system.out.println进行打印,运行结果超时
    return res;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值