美团面试题-C++

  • 美团面试题库,使用C++实现;
// 1 小美的用户名:
#include <iostream>
#include <string>
using namespace std;
/*
input:
    第一行包含一个正整数T,表示需要检验的用户名数量
    接下来有T行,每行一个不超过20的字符串s,表示输入的用户名
output:
    对于每一个输入的用户名s,请输出一行(Wrong or Accept);
Accept:
    1.用户名的首字符必须是大写或者小写字母
    2.用户名只能包含大小写字母,数字
    3.用户名需要包含至少一个字母和一个数字
*/
namespace test01{
    class UserName{
    public:
        int judgeUN(void){
            int num;
            cin>>num;
            while(num--){
                bool flag = false;
                string str;
                cin>>str;
                int len = str.size();
                for(int i = 0; i < len; i++){
                    char c = str[i];
                    bool isLetter = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
                    bool isDigit = c >= '0' && c <= '9';
                    if (i == 0 && !isLetter) break;
                    if (i != 0 && isDigit) flag = true;
                    if (i != 0 && !isLetter && !isDigit) {
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    cout<<"Accept"<<endl;
                } 
                else{
                    cout<<"Wrong"<<endl;
                }
            }
            return 0;
        }
    };
}
// 2 小美的仓库整理:
#include <iostream>
#include <vector>
#include <unordered_map>
/*
输入:
    第一行包含一个正整数n,表示货物的数量
    第二行包含n个正整数,表示1-n号货物的重量w_i
    第三行有n个数,表示小美按顺序取出的货物的编号,也就是一个1-n的全排列
输出:
    包括n行,每行一个整数,表示每取出一件货物以后,对于重量和最大的一堆货物,其重量和为多少
input:
5 
3 2 4 4 5 nums数组
4 3 5 2 1 perm数组(0 1 4 2 3)
output:  ans数组
9 
5 
5 
3 
0
*/
// 解题思路:思想就是将删除过程视为插入过程的逆过程,同时以一些方法维护插入过程的最大区间和 
// 逆序4 3 5 2 1 -> 1 2 5 3 4,表示插入元素的位置顺序,并维护一个最大连续和
namespace test02{
    class storeManage{
    public:
        void ManageStore(){
            int n;
            cin >> n;
            vector<int> nums(n);
            for(int i = 0; i < n; i++){
                cin >> nums[i];
            }
            vector<int> perm(n+1);
            for(int i = n; i >= 1; i--){
                cin >> perm[i];
                perm[i] -- ;   // 将排列从{1:n}转变到{0:n-1} { 0 1 4 2 3 }
            }
            unordered_map<int, int> mark;   // 记录连续区间的另一头
            unordered_map<int, int> sum;   // 记录连续区间的和
            vector<int> ans(n+1);
            ans[0] = 0;

            for(int i = 1; i <= n; i++){
                int v = perm[i];  // 插入的位置
                mark[v] = v;  // 刚插入的时候,v的左右边界都是他本身,直接赋值即可
                sum[v] = nums[v];  // 刚插入的时候,v所在的连续序列和就是他本身
                ans[i] = max(ans[i-1], sum[v]);  // 更新结果集
                for(auto u : {v - 1, v + 1}){  // 遍历左右,看是否存在已经插入的邻居
                    auto it = mark.find(u);
                    if(it != mark.end()){  // 如果i+1的邻居已经存在于表中
                        int x = mark[v], y = mark[u];   // 用x代表v的另一端位置, 用y代表v+i的另一端位置         
                        mark[x] = y;
                        mark[y] = x; // 两个端点分别记录位置
                        sum[x] = sum[y] = sum[x] + sum[y]; // 维护sum数组, 由于是求sum 直接求和即可
                        ans[i] = max(ans[i-1], sum[x]);   // 维护答案
                    }
                }
            }

            for(int i = n - 1; i >= 0; i--){       // 逆序输出答案
                cout<<ans[i];
            }
        }
    };
}
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
// 3 小美的跑腿代购:
/*
input:
    输入第一行包含两个正整数n,m,表示订单的数量和小美可以接的订单数量(1<=n,m<=10000)
    接下来有n行,第i行表示i-1号订单的信息。每行有两个正整数v和w,表示一个订单的跑腿价格和商品重量
output:
    输出包含m个1~n之间的正整数,中间用空格隔开,表示选择的订单编号
*/
namespace test03{
    typedef struct Node{
        int id;  //订单编号
        int value;
        Node() {}
        Node(int id, int v, int w){
            this->id = id;
            value = v + (w*2);
        }
    }node;
    // 按照value的值由大到小进行排序,当value的值相同时,按照id由小到大排序
    bool cmp(node x, node y){
        if(x.value == y.value){
            return x.id < y.id;
        }else{
            return x.value > y.value;
        }
    }
    int main(){
        int n,m;
        cin>>n>>m;
        // 最好使用n初始化goods数组,
        vector<node> goods(n);
        int v = 0;
        int w = 0;
        for(int i = 0; i < n; i++){
            cin >> v >> w;
            goods[i] = Node(i+1, v, w);
        }
        sort(goods.begin(), goods.end(), cmp);  // 当前的goods[i].id符合结果集,但是不是按照id由小到大的顺序排序
        // 选取前m个goods,将其按照id的由小到大的顺序排序
        priority_queue<int, vector<int>, greater<int>> que;
        for(int i = 0; i < m; i++){
            que.push(goods[i].id); // 按照goods[i].id由大到小进入que;
        }
        for(int i = 0; i < m; i++){
            cout<<que.top()<<" ";
            que.pop();
        }
    }
    // 关于优先级队列的使用:
    // 默认情况下使用less<int>即大顶堆(由大到小排序),当使用greater<int>即小顶堆(由小到大排序)
    // 定义: priority_queue<Type, Container, Functional>
    // Type: 数据类型 
    // Container: 容器类型(Container必须是用数组实现的容器,比如vector、deque等等STL里面默认用的是vector) 
    // Functional: 比较的方式(默认less<int>)
}
// 4 小团的复制粘贴:
/*
input:
    第一行包含一个正整数n,表示序列A和序列B的长度
    第二行包含n个正整数,表示序列A中的n个元素,第i个数字表示下标为i的位置上的元素
    第三行是一个操作数m,表示进行的操作数量
        每一步操作:
            粘贴操作:1 k x y 将A序列从下标x位置开始,连续k个元素粘贴到B序列中从下标y开始的连续k个位置
            查询操作:2 x 查询B序列下标x处的值
            eg: 1 2 3 4 A:3 B:4 连续两个 B4 == A3  B5 == A4 
                1 进行操作    2 进行输出
output:
    对于每一个操作2输出一行,每行仅包含一个正整数,表示针对某一个询问的答案
*/
// 方法1:使用有序容器记录所有的复制粘贴操作,一旦遇到查询操作,就从后往前搜索,查询哪次粘贴操作将覆盖到
// 本次查询的位置;假设本次查询的位置为pos,从后往前搜索粘贴操作,if pos between (y,y+k-1),即返回A[x+pos-y]
namespace test04{
    int main(){
        int n;
        cin>>n;
        vector<int> A(n);
        vector<int> B(n,-1);
        for(int i = 0; i < n; i++){
            int num;
            cin>>num;
            A[i] = num;
        }
        int m;
        cin>>m;
        vector<int> vec(m);
        int j = 0;
        while(m>0){
            int a;
            cin>>a;
            if(a == 1){
                int k,x,y;
                cin>>k>>x>>y;
                while(k > 0){
                    B[y - 1] = A[x - 1];
                    y++;
                    x++;
                    k--;
                }
            }
            if(a == 2){
                int x;
                cin>>x;
                cout << B[x - 1] << endl; // 输出
            }
            m--;
        }
        return 0;
    }
}
// 5 小美的区域会议:
/*
input:
    第一行包含两个整数n和k,n表示区域的数量,k表示不能超过的级别
    接下来有n-1行,每行有两个正整数a和b,表示a号区域和b号区域有一条边 (n个区域n-1条边)
    最后一行有n个整数,第i个整数表示i号区域负责人的级别
output:
    符合要求(召集的负责人所在的区域必须构成一个非空的连通的图,这些负责人中,级别最高的和级别最低的相差不超过k)的方案数
    表示可以选择的方案数对10^9+7取模之后的结果
*/
#include <iostream>
#include <vector>
#include <unordered_map>
namespace test05{
    long dfs(unordered_map<int,vector<int>> &tree, vector<bool> &visited, int i, vector<int> &vec, int k,int k0,int i0){
        visited[i] = true;
        long a = 1;
        for(int j : tree[i]){
            if(!visited[j] && vec[j] >= k0 && vec[j]-k0 <= k && (vec[j]>k0||j<i0)) //j号的级别高于i号的级别,j小于i
                a = (a*(1+dfs(tree,visited,j,vec,k,k0,i0)))%1000000007;
        }
        return a;
    }
    int mian(){       
        int n,k;
        cin>>n;
        cin>>k;
        unordered_map<int,vector<int>> tree(n);
        for(int i = 0; i < n - 1; i++){
            int a,b;
            cin>>a>>b;
            tree[a].push_back(b);
            tree[b].push_back(a); //记录每个区域的相邻区域集
        }
        vector<int> vec(n);
        for(int i = 0; i < n; i++){
            int num;
            cin>>num;
            vec.push_back(num);
        }
        long ret;
        for(int i = 0; i < n; i++){
            vector<bool> visited(n);
            long a = dfs(tree,visited,i,vec,k,vec[i],i);
            ret = (ret + a)%1000000007;
        }
        cout<<ret<<endl;
        return 0;
    }
}

// 6 小团的神秘暗号
/*
input:
    第一行是一个正整数n,表示加密后的字符串总长度
    第二行是一个长度为n的仅由大写字母组成的字符串T
output:
    仅包含一个符合要求的最长字符串S
*/
// 要求:头部字符串满足至少包含一个“MT”子序列,且以T结尾、尾部字符串需要满足至少包含一个“MT”子序列,且以M开头;
#include <iostream>
#include <string>
#include <vector>
namespace test06{
    int main(){
        int n;
        cin>>n;
        string str;
        cin>>str;
        string sstr;
        int startpos,endpos;
        int pos1 = str.find("M");
        sstr = str.substr(pos1+1,str.size());
        if(sstr.find("T")!= -1){
            startpos = sstr.find("T");
        }
        sstr = sstr.substr(startpos+1,sstr.size());
        int pos2 = sstr.rfind("T");
        sstr = sstr.substr(0,pos2);
        if(sstr.rfind("M")!= -1){
            endpos = sstr.rfind("M");
        }
        sstr = sstr.substr(0,endpos);
        cout<<sstr<<endl;
        return 0;
    }
}
// 7 小团的选调计划
/*
input:
    第一行是一个正整数n,表示业务骨干和业务区域数量
    接下来有n行,每行n个整数,即一个1~n的排列,第i行表示i-1号业务骨干的意向顺序
output:
    包含n个正整数,第i个正整数表示第i号业务骨干最终去的业务区域编号
*/
#include <iostream>
#include <unordered_map>
using namespace std;
namespace test07
{
    int main() {
        int n;
        cin >> n;
        // 二维数组的初始化规则
        vector<vector<int>> vec(n,vector<int>(n));
        vector<int> res(n);

        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                cin >> vec[i][j];
        
        unordered_map<int, int> umap;
        for (int i = 0; i < n; i++){
            for (int j = 0; j < n; j++) {
                int num = vec[i][j];
                if (!umap.count(num)) {
                    umap[num] = i;
                    res[i] = num;
                    break;
                }
            }
        }
        for (int i = 0; i < n; i++){
            cout << res[i] << " ";
        }
        cout << endl;
        return 0;
    }
} // namespace test07
// 8 小团无路可逃
/*
	1
  2   3
4       5
n:5  x:1  y:2
1: 0 1 1 2 2
2: 1 0 2 1 3
input:
    第一行包含三个整数n,x,y,分别表示树上的结点数量,小美所在的位置和小团所在的位置
    接下来有n-1行,每行两个整数u,v,表示u号位置和v号位置之间有一条边,即u号位置和v号位置彼此相邻
output:
    仅包含一个整数,表示小美追上小团所需的时间
*/
#include <unordered_map>
#include <vector>
#include <iostream>
namespace test08{
    unordered_map<int,vector<int>> umap;
    void dfs(int x, int y, vector<int> &trace){ //参数1表示起始结点 参数2表示可达结点 参数3记录从起始结点到当前结点的最短路径
        trace[x] = trace[y] + 1; //起始结点即结点本身,距离为0
        int len = umap[x].size(); //记录起始结点的周围结点
        for(int i = 0; i < len; i++){
            int z = umap[x][i]; //结点z即起始结点的其中一个周围结点
            if(z == y) continue;
            // trace[1] = 1; 
            // trace[3] = 2;
            // trace[5] = 3;
            // trace[4] = 1;
            dfs(z,x,trace); //以结点2为起始结点,结点1与结点4为周围结点,从起始结点2到结点4的最短路径为1 dfs(4,2,trace) break
            //从起始结点2到结点1的最短路径为1 dfs(1,2,trace)=1 dfs(3,2,trace)=2 dfs(5,2,trace)=3
        }
    }
    int main(){
        int n,x,y; //树上结点数量 小美->小团所在位置(1~n)
        cin>>n>>x>>y; 
         
        for(int i = 0; i < n - 1; i++){ //umap[i]保存树上某一个结点[i]的周围结点vector<int> 
            int u,v;
            cin>>u>>v;
            umap[u].push_back(v);
            umap[v].push_back(u);
        }
        int ret = 0;
        vector<int> trace_x(n+1); //结点x到达其余所有结点的最短路径[0]=-1
        vector<int> trace_y(n+1); //结点y到达其余所有结点的最短路径[0]=-1
        trace_x[0] = trace_y[0] = -1;
        dfs(x,0,trace_x); 
        dfs(y,0,trace_y);
        for(int i = 1; i <= n; i++){ //i=1~n
            if(trace_y[i] < trace_x[i]){ //当结点y到达的某一个结点比结点x快时,才符合小美追逐小团的条件
                ret = max(ret, trace_x[i]);
            }
        }
        cout<<ret;
        return 0;
    }
}
// 9 小团的装饰品
/* 
m个空位
a[1] a[2] ... a[m] 
a[x]<=n 空位i,j上的装饰品的价格需要满足:a[i] <= a[j] && a[j]%a[i]=0 && a[i]<=n && a[j]<=n
cin>>m,n
input:
    n和m(装饰品的最大价值 空位) 
output:
    一个数,结果对998244353取模,表示购买的方案数
*/
/*
动态规划,dp[i][j]表示第i个物品房价格为j的装饰品时有多少种方案
当我们在确定第i个装饰物时,其实它的价格是有限制的,如果第i-1个装饰物价格为j,那么第i个装饰物的价格只能是j的整数倍,且不能超过n。
而第i个装饰物对于任意确定的价格k=j*times,可能存在多组(j, times)乘积相同,把这些方案数全部加起来才能得到dp[i][k],因此状态转移方程为:
dp[i][j*times] = dp[i][j*times] + dp[i - 1][j] (times为整数,满足j*times<=n)
最后将第m个装饰物的所有价格的方案数加起来就是我们要求的方案总数
*/
namespace test09{
    int main(){
        int n,m;
        cin>>n>>m;
        const int mod = 998244353;
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));
        for(int i = 1; i <= n; i++){
            dp[1][i] = 1; 
        }
        for(int i = 2; i <= m; i++){ //第i个位置
            for(int j = 1; j <= n; j++){ //第i个位置装饰品的价值 dp[i][j*times] = dp[i-1][j] + dp[i][j*times];
                for(int k = 1; j*k <= n; k++){
                    dp[i][j*k] =  (dp[i-1][j] + dp[i][k*j])%mod;
                }
            }
        }  
        int ret = 0;  
        for (int i = 1; i <= n; ++i) {
            ret = (ret + dp[m][i]) % mod;
        }
        cout<<ret;
        return 0;
    }
}


int main(){
    // test01::UserName obj1;
    // obj1.judgeUN();

    test02::storeManage obj2;
    obj2.ManageStore();
    return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值