美团秋招笔试五道编程(2021-08-08)

恭喜发现宝藏!微信搜索公众号【TechGuide】关注更多新鲜好文和互联网大厂的笔经面经。
作者@TechGuide【全网同名】
点赞再看,养成习惯,您动动手指对原创作者意义非凡🤝

第一道: 找数(100%)

小美和小团在玩游戏。小美将会给出 n 个大小在 1 到 n 之间(包括 1 和 n)的整数,然后小美会再告诉小团一个整数 k,小团需要找到一个最小的整数 x 满足以下条件:
整数x的大小在 1 到 n 之间(包括1和n)
在小美给出的 n 个整数中,恰好有 k 个数严格比 x 小
输入描述
第一行是一个数 T,表示有 T 组数据。
对于每组数据:
第一行有两个整数 n 和 k,分别表示小美将会给出 n 个数以及她给出的整数k。

接下来一行有 n 个用空格隔开的正整数,表示小美给出的 n 个正整数。
输出描述
对于每组数据:
如果存在满足要求的数 x,第一行先输出 “YES”(不含引号),第二行输出数 x 的值。
如果不存在满足要求的数 x,输出 “NO”(不含引号)。

样例输入

1
2
3
4
5
2
6 6
1 6 6 2 1 3
6 3
1 6 5 2 2 5

样例输出

1
2
3
NO
YES
3

提示

数据范围和说明
30%的数据保证 n<=10, 0<=k<=n, T<=10
60%的数据保证 n<=1000, 0<=k<=n, T<=10
100%的数据保证 n<=100000, 0<=k<=n, T<=10

java版

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for(;t > 0; t--){
            int n = sc.nextInt();
            int k = sc.nextInt();
            int[] nums = new int[n];
            for (int i = 0; i < nums.length; i++) {
                nums[i] = sc.nextInt();
            }
            int ans = fun(nums, n, k);
            if(ans == -1) System.out.println("NO");
            else{
                System.out.println("YES");
                System.out.println(ans);
            }
        }
    }

    private static int fun (int[] nums, int n, int k) {
        Arrays.sort(nums);
        for (int x = 1; x <= n; x++) {  // 穷举 x
            int xiao = 0;
            int da   = 0;
            for (int j = 0; j < nums.length; j++) {
                if(nums[j] > x) da++;
                if(nums[j] < x) xiao++;
            }
            if(xiao == k) return x;
        }
        return -1;
    }
}

CPP版

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int N, K;


int main(){
    
    int T ;
    cin>>T;
    while(T--){
        cin>>N >> K;
        vector<int> data(N);
        for(int i=0;i<N;i++)
            cin >> data[i];
        sort(data.begin(), data.end());

        int ans;

        if(K>N){
            cout<< "NO" <<endl;
            continue; 
        }

        if(K==0)
            ans = 1;
        else
            ans = data[K-1] + 1;
        
        if(ans < 1 || ans > N){
            cout<<"NO"<<endl;
            continue;
        }
        
        if(K<N && data[K-1]==data[K]){
            cout<< "NO" <<endl;
            continue;
        }
        
        cout<<"YES"<<endl;
        cout<<ans<<endl;
    }
}

Python版

T = int(input())
for _ in range(T):
    n, k = map(int, input().split())
    num = list(map(int,input().split()))
    num.sort()
    if n==k:
        if num[n-1]+1 <= n:
            print(num[n-1]+1)
        else:
            print('NO')
    else:
        # 主要报错部分
        if num[k-1]+1 >= 1 and num[k-1]+1 <= n and num[k-1]+1 <= num[k]:
            print('YES')
            print(num[k-1]+1)
        else:
            print('NO')

第二道:奇怪键盘(100%)

小美得到了一个奇怪的键盘,上面一共有 53 个按键,包括 26 个小写字母、26 个大写字母和空格。这个键盘的奇怪之处如下:
当小美按下一个按键时,该按键可能会被多次触发,即输出一连串按下按键所对应的字符。
键盘会时不时地自动按下空格键。
在使用这个键盘来进行输入时,小美保证了相邻两次按下的按键一定不同以及不主动按下空格键,现在给你小美使用这个键盘输入一个字符串后得到的结果,请你还原小美原本想要输入的这个字符串。

输入描述
一行,一个包含小写字母、大写字母和空格的字符串,表示小美输入后得到的结果。

输出描述
输出一行,表示小美原本想要输入的字符串。

样例输入

1
a iC C  C GmyyyySp p

样例输出

1
aiCGmySp

提示

数据范围和说明
30%的数据保证 输入的字符串长度<=20
60%的数据保证 输入的字符串长度<=1000
100%的数据保证 输入的字符串长度<=100000

java版本

import java.util.Scanner;

public class Main {
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        String b = s.trim();
        StringBuilder sb = new StringBuilder(b);
        for(int i = 1; i < sb.length(); i++){
            if(sb.charAt(i) == ' '){
                sb.deleteCharAt(i);
                i--;
            }
        }
        for (int i = 1; i < sb.length(); i++) {
            if(sb.charAt(i) == sb.charAt(i-1)){
                sb.replace(i-1, i, " ");
            }
        }
        for(int i = 1; i < sb.length(); i++){
            if(sb.charAt(i) == ' '){
                sb.deleteCharAt(i);
                i--;
            }
        }
        System.out.println(sb);
    }
}

CPP版

#include<iostream>
#include<vector>
 
using namespace std;
 
int main(){
    string str;
    getline(cin,str);
    string ret;
    for(int i=0 ; i<str.size() ;i++){
        if(str[i] == ' ')
            continue;
        else{
            ret+=str[i];
            int tmp = i+1;
            while( tmp <str.size() && (str[tmp] == str[i] || str[tmp] == ' ') )
                tmp++;
            i = tmp-1;
        }
    }
    cout<<ret<<endl;
    return 0;
}

Python版

a = str(input())
ans1 = []
ans = []
# 删除空格
for i in range(len(a)):
    if a[i] != ' ':
        ans1.append(a[i])
# 删除重复元素
for j in range(len(ans1)):
    if j==0:
        ans.append(ans1[0])
    elif ans1[j] != ans1[j-1]:
        ans.append(ans1[j])
# 列表转化为字符串
out = ''.join(b for b in ans)
print(out)

第三道 序列问题(100%)

小美有一个长度为 n 的序列 A,A[i] 表示序列中第 i 个数(1<=i<=n)。她定义序列中第 i 个数的 prev[i] 值 为前 i-1 个数中比 A[i] 小的最大的值,即满足 1<=j<i 且 A[j]<A[i] 中最大的 A[j],若不存在这样的数,则 prev[i] 的值为 0。现在她想要你帮忙计算对于所有的 i,prev[i]*i 之和是多少。

输入描述
第一行是一个整数 n 表示序列的长度。
接下来一行 n 个数用空格隔开,第 i 个数表示 A[i] 的大小。

输出描述
一行一个整数,表示答案。

样例输入

1
2
5
1 6 3 3 8

样例输出

1
39

提示
数据范围和说明
30%的数据保证 n<=20,1<=A[i]<=100。
60%的数据保证 n<=1000,1<=A[i]<=1000。
100%的数据保证 n<=100000,1<=A[i]<=100000。

建图,答案是节点数-连通块数。对于a[i],找到之前小于它的最大的数,可以维护一个set,每次处理完当前a[i],就插入到set中。对于处理,可以直接利用set的lower_bound(val),然后根据迭代器减1判断情况。

CPP版

#define  ll long long;
using namespace std;

int main() {
    int n;
    scanf("%d",&n);
    set<int> st;
    long long ans = 0;
    for (int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        if (st.size()){
            auto it= lower_bound(st.begin(),st.end(),x);
            it--;
            if (it!=st.end()){
                ans+=i*(*it);
            }
        }
        st.insert(x);
    }
    cout<<ans<<endl;
    return 0;
}

java版

public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long sum = 0;
        int[] nums = new int[n];
        for(int i = 0; i < n; i++){
            nums[i] = sc.nextInt();
        }
        int[] prev = new int[n];
        TreeSet<Integer> set = new TreeSet<>();
        for(int i = 0; i < n; i++){
            int temp = nums[i];
            Integer top = set.floor(temp);
            if(top == null){
                prev[i] = 0;
            }else{
                if(temp == top){
                    set.remove(temp);
                    Integer nextTmp = set.floor(temp);
                    prev[i] = nextTmp == null ? 0 : nextTmp;
                    set.add(temp);
                }else{
                    prev[i] = top;
                }
            }
            set.add(temp);
        }
        for(int i = 1; i < n; i++){
            sum += (i + 1) * prev[i];
        }
        System.out.println(sum);
    }

第四道 最少操作次数(100%)

小美给了小团一个长度为 n(n为偶数)的序列 A,序列中的数都是介于 [1,100000] 的整数。小团想把这个序列变得漂亮后再送回给小美。小美觉得一个序列是漂亮的当且仅当这个序列的前一半和后一半是一样的,即对于 1<=i<=n/2 都满足 A[i]==A[i+n/2]。
小团可以按进行以下操作任意次:
选择两个介于 [1, 100000] 之间的数 x 和 y,然后将序列 A 中所有值为 x 的数替换为 y。
注意,每次操作都会在上一次操作后得到的序列上进行。小团想知道他最少需要操作多少次可以把序列变成漂亮的。

输入描述
第一行是一个整数 n,表示序列的长度。数据保证 n 为偶数。
第二行有 n 个用空格隔开的整数,第 i 个数表示 A[i] 的值。数据保证 1<=A[i]<=100000。

输出描述
输出小团需要的最少操作次数。

样例输入

1
2
10
4 2 1 5 2 10 2 1 5 8

样例输出

1
2

提示
数据范围和说明
30%的数据保证 n<=10,1<=A[i]<=10000。
70%的数据保证 n<=1000,1<=A[i]<=10000。
100%的数据保证 n<=100000,1<=A[i]<=10000。

任选x修改为y,使得序列前一半与后一半相同,可以处理出不同的 pair{ a[i] , a[i+n/2] },然后默认first为较小值,去一下重 ( 相同的对计算一次贡献 ),然后建立无向图。优先从入度小的点出发DFS,每走一步就是一个花费,图遍历完就得答案。
并查集

Java版

public class Main {
    private static int x = 10001;
    private static int[] next = new int[x], count = new int[x];
    public static void main(String[] args) {
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
        Scanner s = new Scanner(System.in);
        int n = s.nextInt();
        int[][] tmp = new int[n/2][2];
        for (int i = 0; i < n / 2; i++) tmp[i][0] = s.nextInt();
        for (int i = 0; i < n / 2; i++) tmp[i][1] = s.nextInt();
        for (int i = 0; i < next.length; i++) {
            next[i] = i;
            count[i] = 1;
        }
        for (int i = 0; i < n / 2; i++) {
            if (tmp[i][0]!=tmp[i][1]){
                union(tmp[i][0],tmp[i][1]);
            }
        }
        int res = 0;
        for (int i = 0; i < x; i++) {
            if (i==find(i)) res += (count[i]-1);
        }
        System.out.println(res);
    }
    private static void union(int i, int j){
        int ii = find(i);
        int jj = find(j);
        if (ii==jj) return;
        if (count[ii]>count[jj]){
            next[jj] = ii;
            count[ii] += count[jj];
        }else{
            next[ii] = jj;
            count[jj] += count[ii];
        }
    }
    private static int find(int i){
        while(next[i]!=i) i = next[i];
        return i;
    }
}

CPP版

#include<iostream>
#include<vector>
#include<algorithm>
 
using namespace std;
 
int getIndex(vector<int>& tree , int num){
    int l = 0 , r = tree.size() -1;
    while(l<r){
        int mid = (l+r)>>1;
        if(tree[mid] == num)
            return mid;
        if(tree[mid] > num)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
 
int findroot(vector<int> & tree , int x){
    if(tree[x] != -1){
        tree[x] = findroot(tree,tree[x]);
        return tree[x];
    }else
        return x;
}
 
int main(){
    int N;
    cin>>N;
    vector<int> data(N);
    for(int i=0;i<N;i++)
        cin>>data[i];
 
    vector<int> tmp(data);
    sort(tmp.begin(),tmp.end());
    tmp.erase( unique(tmp.begin(),tmp.end()) , tmp.end());
     
    vector<int> tree(tmp.size(),-1);
 
    int ans = 0;
 
    for(int i=0;i<N/2 ;i++){
        if(data[i] != data[i+N/2]){
            int x = getIndex(tmp,data[i]) , y = getIndex(tmp,data[i+N/2]);
            int xroot = findroot(tree,x) , yroot = findroot(tree,y);
            if(xroot!=yroot){
                tree[xroot] = yroot;
                ans++;
            }
        }
    }
    cout<< ans <<endl;
    return 0;
}

第五道:对换左右子树(100%)

交换二叉树的左右孩子节点然后输出中序遍历结果。可以直接用数组表示存二叉树,点值对应题目要求的点序号,下标0开始,初始时左右儿子分别为2x+1,2x+2,然后根据修改,分别修改Lchild和Rchild的指向。第五题代码还没删掉,如下。

#include<bits/stdc++.h>
using namespace std;
int a[100020];
typedef pair<int,int> pii;
int n,m,k;
int loc[100020];
struct node{
    int val;
    int L,R;
}p[10000];
struct pre{
    int L,R;
}has[10000];
void solve(int x) {
    if(x>=n) return;
    loc[p[x].val]=x;
    p[x].L=p[x].R=0;
    int cur=p[x].val;
    int Lval=has[cur].L;
    int Rval=has[cur].R;
    if(Lval) {
        p[x].L=2*x+1;
        p[2*x+1].val=Lval;
        solve(2*x+1);
    }
    if(Rval) {
        p[x].R=2*x+2;
        p[2*x+2].val=Rval;
        solve(2*x+2);
    }
}
void print(int x) {
    if(p[x].L) print(p[x].L);
    cout<<p[x].val<<" ";
    if(p[x].R) print(p[x].R);
}
int main()
{
    cin>>n>>m>>k;
    p[0].val=k;
    for(int i=1;i<=n;i++) {
        cin>>has[i].L>>has[i].R;
    }
    solve(0);
    for(int i=1;i<=m;i++) {
        int x;
        cin>>x;
        int id=loc[x];
        swap(p[id].L,p[id].R);
    }
    print(0);
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechGuide

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值