【2022-08-27】美团秋招笔试前四道编程题

恭喜发现宝藏!搜索公众号【TechGuide】回复公司名,解锁更多新鲜好文和互联网大厂的笔经面经,目前已更新至美团、微软…
作者@TechGuide【全网同名】
点赞再看,养成习惯,您动动手指对原创作者意义非凡

第一题:神奇字符

题目描述

小美在摆弄她的字符串。最近小团送了小美一个特殊字符 ’ * ',这个字符可以和其他所有字符匹配,除了这个字符外,其他字符只能自己和自己匹配。 小美先前有一个字符串S,长度为n,现在她又新组合了一个可有特殊字符 ’ * ’ 的字符串s,长度为m。

小美想知道有多少个位置 i,使得S[i+j]与s[j]对于1≤j≤m均能匹配上?

其中X[y]代表字符串X中第y位的字符。

输入描述

第一行两个空格隔开的正整数n和m,分别表示字符串S和字符串s的长度。 接下来一行长度为n的仅包含小写英文字母的字符串S 接下来一行长度为m的包含小写英文字母以及特殊字符 ’ * ’ 的字符串s 对于所有数据,1≤m≤n≤2000

输出描述

输出一行一个整数,表示满足要求的位置数量

代码

CPP版本

直接暴力

#include 

using namespace std;

int main(int argc, char* argv[]) {
    int n, m;
    cin >> n >> m;
    string a, b;
    cin >> a >> b;
    int ret = 0;
    for (int i = 0; i + m - 1< n; ++ i){
        int ok = 1;
        for (int j = 0; j < m; ++ j){
            ok &= (a[i + j] == b[j] || b[j] == '*');
        }
        ret += ok;
    }
    cout << ret << endl;
    return 0;
}
// vx公众号关注TechGuide 实时题库 闪电速递

Python版本

n, m = map(int, input().strip().split())
str1 = list(map(str, input().strip().split()))[0]
str2 = list(map(str, input().strip().split()))[0]
pos = 0
def isValid(str1, str2):
    for i in range(m):
        if str2[i] == '*':
            continue
        if str1[i] != str2[i]:
            return False
    return True
pos = 0
if n < m:
    print(pos)
else:
    for i in range(n-m+1):
        if isValid(str1[i:i+m], str2):
            pos += 1
            print(str1[i:i+m])
    print(pos)
# vx公众号关注TechGuide 实时题库 闪电速递

第二题:挑剔

题目描述

小美有一个精致的珠宝链子。初始这个链子上有n个宝石,从左到右分别编号为1~n (宝石上的编号不会因为交换位置而改变编号)。 接着,小美为了美观对这个项链进行微调,有m次操作,每次选择一个编号 x ,将编号 x 的宝石放到最左边(不改变其他宝石的相对位置)。 小美想知道,所有操作完成后最终链子从左到右宝石编号是多少。

输入描述

第一行两个正整数n和m,分别表示链子上的宝石数和操作次数。 接下来一行m个数 x1,x2,…,xm ,依次表示每次操作选择的编号x值。 数字间两两有空格隔开 对于所有数据,1≤m,n≤50000, 1≤xi≤n

输出描述

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

思路

记录下每个数字最后一次被修改的时间戳,最后sort一边就可以了

代码

CPP版本

#include 

using namespace std;

int main(int argc, char* argv[]) {
    int n, m;
    cin >> n >> m;
    vector<pair<int, int> > vec(n);
    for (int i = 0; i < n; ++ i){
        vec[i] = make_pair(i + 1, 0);
    }
    for (int i = 1; i <= m; ++ i){
        int x; cin >> x;
        vec[x - 1].second = i;
    }
    sort(vec.begin(), vec.end(), [](const pair<int, int>& L, const pair<int, int>& R) {
        if (L.second != R.second) {
            return L.second > R.second;
        } else {
            return L.first < R.first;
        }
    });
    for (int i = 0; i < n; ++ i) cout << vec[i].first << " \n"[i == n - 1];
    return 0;
}
// vx公众号关注TechGuide 实时题库 闪电速递

Python版本

n, m = map(int, input().strip().split())
operator = list(map(int, input().strip().split()))
# print(operator)
ori_arr = list(range(1, n+1))
res = operator[::-1]
# for num in ori_arr:
#     if num not in res:
#         res.append(num)
# print(res)
tmp = [i for i in ori_arr if i not in res]
res = res + tmp
res = list(map(str, res))
print("".join(res))
# vx公众号关注TechGuide 实时题库 闪电速递

第三题:裁缝

题目描述

小团最近获得了美美团团国的裁缝资格证,成为了一个裁缝!现在小团有一个长度为n的大布料S(在这个国家布料其实是一个仅包含小写英文字母的字符串), 小团可以将布料在任意位置剪切,例如布料abcd可以被裁剪为a与bcd 或ab与cd或abc与d ,不过,裁剪完之后是不能拼接起来的,因为小团还不是很擅长拼接布料。

现在小团想知道能不能有一种裁剪方式能让他把布料恰好裁剪成客人要求的小布料。 形式化地,有一个串S,问是否能将其划分成m个不相交的连续子串,使得这些连续子串可以与要求的连续子串一 一对应。 两个串相对应是指这两个串完全相等。例如"aab"=“aab” 但 “aab"≠"baa”

输入描述

第一行两个空格隔开的正整数n和m,分别表示大布料S长度和客人要求的小布料数量。 接下来一行一个长度为n的仅包含小写英文字母的串S,表示大布料的组成。 接下来一行m个空格隔开的数x1,x2, …,xm ,依次表示所要求的小布料长度。 接下来开始m行,每行一个长度为xi的仅包含小写英文字母的串si,表示第i个小布料的组成。

输出描述

如果存在这样的方案,输出方案总数。如果不存在任何方案,输出0。

两个方案A、B不相同当且仅当方案A中存在一个相对于原始长布料的裁剪位置i,而方案B中并未在该位置i裁剪。 例如aaaaaa 裁剪方案aaa|aaa 与方案 aaa|aaa是相同的方案。而方案aa|aaaa与方案aaaa|aa是不同的方案,虽然划分出的结果都是aa与aaaa, 但前者在第二个a处进行了裁剪,后者并没有在这里进行裁剪,所以视为不同的裁剪方案。

思路

全排列暴力枚举,注意不同的排列对应的切割方式可能是一致的,我直接塞进set去重了

代码

CPP版本

#include 

using namespace std;

string S;
vector<string> T;

int main(int argc, char* argv[]) {
    int n, m;
    cin >> n >> m;
    cin >> S;
    for (int i = 1, x; i <= m; ++ i) cin >> x;
    T.resize(m);
    for (int i = 1; i <=m;++ i) {
        cin >> T[i - 1];
    }
    int ret = 0;
    vector<int> id(m);
    iota(id.begin(), id.end(), 0);
    set<vector<int> > sol;
    do {
        int ok = 1;
        for (int i = 0, j = 0; i < m && ok; ++ i) {
            int len = 0;
            int index = id[i];
            while (len < T[index].size() && T[index][len] == S[j]) {
                ++ j;
                ++ len;
            }
            ok &= (len == T[index].size());
        }
        if (ok) {
            vector<int> o;
            for (int i = 0; i < m; ++ i){
                o.push_back(T[id[i]].size());
            }
            sol.insert(o);
        }
    } while(next_permutation(id.begin(), id.end()));
    cout << sol.size() << endl;
    return 0;
}
// vx公众号关注TechGuide 实时题库 闪电速递

Python版本

from collections import Counter
n, m = map(int, input().strip().split())
str_long = list(map(str, input().strip().split()))[0]
arr_s = list(map(int, input().strip().split()))
bu_s = []
for i in range(m):
    bu_s.append(list(map(str, input().strip().split()))[0])
# print(bu_s)
def isValid(s1, s2):
    return Counter(s1) == Counter(s2)
res = []
path = []
def backtrace(s1, path, startidx):
    if startidx>len(s1):
        return
    if len(path)==m and isValid(path, bu_s):
        res.append(path[:])
    for i in range(startidx, len(s1)):
        path.append(s1[startidx:i + 1])
        backtrace(s1, path, i + 1)
        path.pop()
backtrace(str_long, path, 0)
print(len(res))
# vx公众号关注TechGuide 实时题库 闪电速递

第四题:下雨

题目描述

小团正忙着用机器人收衣服!因为快要下雨了,小团找来了不少机器人帮忙收衣服。他有n件衣服从左到右成一行排列,所在位置分别为1~n, 在每个位置上已经有一个就绪的机器人可以帮忙收衣服,但第 i 个位置上的机器人需要pi的电量来启动,然后这个机器人会用ti的时间收衣服, 当它收完当前衣服后,会尝试去收紧邻的右边的一件衣服(如果存在的话),即 i+1处的衣服,如果 i+1 处的衣服已经被其他机器人收了或者其他机器人正在收,这个机器人就会进入休眠状态,不再收衣服。不过如果机器人没有休眠,它会同样以ti时间来收这件 i+1 处的衣服(注意,不是ti+1的时间,收衣服的时间为每个机器人固有属性),然后它会做同样的检测来看能否继续收 i+2 处的衣服,一直直到它进入休眠状态或者右边没有衣服可以收了。

形象地来说,机器人会一直尝试往右边收衣服,收k件的话就耗费k*ti的时间,但是当它遇见其他机器人工作的痕迹,就会认为后面的事情它不用管了,开始摸鱼,进入休眠状态。 小团手里总共有电量b,他准备在0时刻的时候将所有他想启动的机器人全部一起启动,过后不再启动新的机器人,并且启动的机器人的电量之和不大于b。 他想知道在最佳选择的情况下,最快多久能收完衣服。若无论如何怎样都收不完衣服,输出-1。

输入描述

第一行两个正整数n和b,分别表示衣服数量和小团持有电量。 接下来一行n个数 p1,p2, …,pn ,含义如题所述,为机器人唤醒需求电量。 接下来一行n个数 t1,t2, …,tn,含义如题所述,为机器人收衣服所需时间。 数字间两两有空格隔开。 对于所有数据,1≤n≤1000,1≤pi≤100, 1≤ti , b≤10^5

输出描述

输出最短所需时间。

思路

暴力dp显然过不去,考虑二分总时间
check的时候根据当前二分出来的时间限制做背包,求出在当前最大时间限制下需要的最少能量,最后和总能量限制比较

代码

CPP版本

#include 

using namespace std;

int n, M;

int main(int argc, char* argv[]) {
    cin >> n >> M;
    vector<int> p(n + 1);
    for (int i = 1; i <= n; ++ i) cin >> p[i];
    vector<int> t(n + 1);
    for (int i = 1; i <= n; ++ i) cin >> t[i];
    if (p[1] > M) {
        cout << -1 << endl;
        return 0;
    }
    int l = 1, r = 1e9, ret = 1e9;
    auto check = [&](int mid) -> bool {
        vector<int> dp(n + 2, 1e9);
        dp[n + 1] = 0;
        for (int i = n; i >= 1; -- i) {
            for (int j = n + 1; j > i; -- j) {
                if (t[i] * (j - i) <= mid) {
                   dp[i] = min(dp[i], dp[j] + p[i]);
                }
            }
        }
        return dp[1] <= M;
    };
    while (l <= r) {
        int mid = (l + r) / 2;
        if (check(mid)) {
            ret = mid;
            r = mid - 1;
        } else l = mid + 1;
    }
    cout << ret << endl;
    return 0;
}
// vx公众号关注TechGuide 实时题库 闪电速递

你可能感兴趣的:(大厂编程题,c++,算法,开发语言)