【牛客网笔试整理】美团点评 笔试整理

链接:https://www.nowcoder.com/questionTerminal/29d1622d47514670a85e98a1f47b8e2d
来源:牛客网

已知一种新的火星文的单词由英文字母(仅小写字母)组成,但是此火星文中的字母先后顺序未知。给出一组非空的火星文单词,且此组单词已经按火星文字典序进行好了排序(从小到大),请推断出此火星文中的字母先后顺序。

链接:https://www.nowcoder.com/questionTerminal/29d1622d47514670a85e98a1f47b8e2d
来源:牛客网

输入描述:
一行文本,为一组按火星文字典序排序好的单词(单词两端无引号),单词之间通过空格隔开

输出描述:
按火星文字母顺序输出出现过的字母,字母之间无其他字符,如果无法确定顺序或者无合理的字母排序可能,请输出"invalid"(无需引号)

示例一

输入
z x
输出
zx

示例2

输入
wrt wrf er ett rftt
输出
wertf

示例3

输入
z x z
输出
invalid

我每次做笔试题,看到题目长就可能静不下心去看题,其实和做数学题一样,题目越长越要静下心来分析,挖掘关系

这道题的题目让求火星文中的先后顺序;
顺序由已知的字符串来决定;
具体规则:给出的字符串按从小到大排序;

此时我们根据示例求解;
z x
因为z写在了x前面;所以输出为zx

wrt wrf er ett rftt
这道题大家可能有些疑惑,rftt不是将f写在了t前面,那顺序是不是werft呢,但是答案是wertf
我们仔细思量一下,题目中说的是此组单词按照火星文字典序进行了排序,记住,是此组,不是每一个字母中的每一个字符都按照大小排序,它保证的是前一个字符总体小于后一个字符,可以把第一个字符看成一级比较,二级,三级……一次类推,首先第一个字符进行大小比较再进行第二个字符比较,根据题目中wrt 和 wrf 可以发现,t在f的后面,因为e在r的前面,所以后两个字符的顺序已经确定,而倒推法,加入f在t的前面,那么前两个字符串因为前两个字符相同,那么会wrf wrt这样排序,势必和原题相反,所以,我们比较的根据是前一个和后一个字符的第一个不同的字符来排序

public class IsSort {
    //用map记录图,因为有26个字符,直接用二维数组可以表示横纵坐标(两个字符)之间的关系,
    private static int[][]map=new int[26][26];
    //用来记录当前字符是否是图中的,图中有且未被选为1,已被选即为0
    private static int[]indegree=new int[26];
    //标记数组,标记字符是否在图中出现
    private static boolean[]flag=new boolean[26];
    //set集合用来加入字符,统计字符个数,好处是去重
    private static Set<Character> set=new HashSet<>();
    //结果集
    private static List<Character> ans=new ArrayList<>();


    public static void main(String[] args) {

        Scanner sc=new Scanner(System.in);
        String[]input=sc.nextLine().split(" ");//生成数组
        //int maxLen=0;
        //创建图
        build(input);
        //进行排序
        topolpgy();
        if(ans.size()==set.size()){
            for(Character c:ans){
                System.out.print(c);
            }
        }else {
            System.out.println("invalid");
        }
    }

    private static void build(String[] strs) {
        String pre=strs[0];//将前一个字符保存
        for(char c:pre.toCharArray()){
            set.add(c);//加入set集合
        }
        for(int i=1;i<strs.length;i++){
            String cur=strs[i];//将当前字符记录
            for(char c:cur.toCharArray()){
                set.add(c);//将不同字符加入
            }
            //循环比较第一个不同的元素,并且加入map
            for(int j=0;j<Math.min(pre.length(),cur.length());j++){
                if(pre.charAt(j)==cur.charAt(j)) continue;//如果相同就继续
                if(map[pre.charAt(j)-'a'][cur.charAt(j)-'a']==1)break;//说明这组数据已经加入过图了,没必要
                map[pre.charAt(j)-'a'][cur.charAt(j)-'a']=1;//值设为1,说明pre.charAt(j)-'a'<cur.charAt(j)-'a'
                indegree[cur.charAt(j)-'a']+=1;//向后标记,标记当前数组中的那个不同的字符出现的次数,也就是稍大一点的
                flag[pre.charAt(j)-'a']=true;//标记,用来得知在图中已经有了
                flag[cur.charAt(j)-'a']=true;
                break;//因为我们只要得知第一个不同的字符即可,所以直接break
            }
            pre=cur;//维护pre
        }
    }

    private static void topolpgy() {
        //set中的个数就是所有字符的个数
        while (ans.size()<set.size()){
            //先找到第一个字符,因为当时标记是 indegree[cur.charAt(j)-'a']+=1;所以第一个字符串的那个不同的字符就漏掉了,也就是最小的那个
            int cnt=0;
            for(int i=0;i<indegree.length;i++){
                if(indegree[i]==0&&flag[i]) cnt++;
            }
            if(cnt!=1)break;//也就是说如果找到的不是一个,就是错的
            //开始找
            for(int i=0;i<indegree.length;i++){
                if(indegree[i]==0&&flag[i]){//第一次循环找到的就是最小的字符,而后每次操作indegree[j]--,所以再找就是下一个最小的
                    ans.add((char)('a'+i));//按顺序加入
                    flag[i]=false;//已经加入结果集,所以设为false
                    for(int j=0;j<26;j++){//在二维数组中找i这个字符和j字符之间的大小关系
                        if(map[i][j]==0)continue;//是0说明没关系
                        indegree[j]--;//将j出现的次数-1
                        map[i][j]=0;//维护map,置为0
                    }
                }
            }
        }
    }



}

这是代码,是看评论区写的;
没看懂别着急;
一步一步来带你调试,还原程序运行的过程;

build函数

wrt wrf
首先是这两个字符开始比较
map[t][f]=1;(这里使用字符,真正执行是转化成数字哦)
indegree[f]=1;
flag(t)=true;
flag(f)=true;
wrf er
map[w][e]=1;
indegree[e]=1;
flag(w)=true;
flag(e)=true;
er ett
map[r][t]=1;
indegree[t]=1;
flag(r)=true;
flag(t)=true;
ett rftt
map[e][r]=1;
indegree[r]=1;
flag(e)=true;
flag(r)=true;

topolpgy函数

根据indegree[i]==0&&flag[i]第一次找到最小
map[22][4]即map[w][e]=1,且indegree[w]没有标记过
ans.add(w);
indegree[e]--;
map[w][e]=0;

因为上一步操作将indegree[e]--;所以变为0
这次找到的就是map[e][r];
ans.add(e);
indegree[r]--;
map[e][r]=0;

以此类推,其实横纵坐标就保证了有序性。

2110年美团外卖火星第3000号配送站点有26名骑手,分别以大写字母A-Z命名,因此可以称呼这些骑手为黄家骑士特工A,黄家骑士特工B…黄家骑士特工Z,某美团黑珍珠餐厅的外卖流水线上会顺序产出一组包裹,美团配送调度引擎已经将包裹分配到骑手,并在包裹上粘贴好骑手名称,如RETTEBTAE代表一组流水线包裹共9个,同时分配给了名字为A B E R T的5名骑手。请在不打乱流水线产出顺序的情况下,把这组包裹划分为尽可能多的片段,同一个骑手只会出现在其中的一个片段,返回一个表示每个包裹片段的长度的列表。

链接:https://www.nowcoder.com/questionTerminal/80fdfb1b65e149959fc1088bd3f9692e
来源:牛客网

输入描述:
输入数据只有一行,为一个字符串(不包含引号),长度不超过1000,只包含大写字母’A’到’Z’,字符之间无空格。

输出描述:
输出每个分割成片段的包裹组的长度,每个长度之间通过空格隔开

示例1

输入
MPMPCPMCMDEFEGDEHINHKLIN
输出
9 7 8

说明
划分结果为MPMPCPMCM,DEFEGDE,HINHKLIN。

每个骑手最多出现在一个片段中。

像MPMPCPMCMDEFEGDE,HINHKLIN的划分是错误的,因为划分的片段数较少。

这道题是求划分字段开始的下标;
我一开始的想法是将每个字符的下标存入map中,以map<String,List>的形式存储,然后因为不知怎么控制退出条件,然后就没有做下去了
看了评论之后,发现答主双指针用的很妙;

public static void cutLen(String s){
        int i=0,j=0,len=s.length();
        while (j<len){
            char c=s.charAt(j);
            int tail=s.lastIndexOf(c);
            int pre=j;
            i=j+1;
            j=tail;
            while (i<j){
                char inner=s.charAt(i);
                j=Math.max(j,s.lastIndexOf(inner));
                i++;
            }
            j++;
            System.out.print(j-pre+" ");
        }

    }
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String s=sc.nextLine();
        cutLen(s);

    }

打车派单场景, 假定有N个订单, 待分配给N个司机。每个订单在匹配司机前,会对候选司机进行打分,打分的结果保存在N*N的矩阵A, 其中Aij 代表订单i司机j匹配的分值。

假定每个订单只能派给一位司机,司机只能分配到一个订单。求最终的派单结果,使得匹配的订单和司机的分值累加起来最大,并且所有订单得到分配。

示例1
输入
3
1.08 1.25 1.5
1.5 1.35  1.75
1.22 1.48 2.5
输出
5.25
1 2
2 1
3 3

这道题我走了几个坑,应该是找到最大值,而我找的是每一列的最大值

和二维数组有关的好多都是DFS,回溯;比如机器人路径问题,n皇后问题;

这道题需要行和列一起结合来考虑;
这种DFS问题好难啊;

import java.util.Scanner;

public class Main {

    static double[][] order;
    static boolean[] isAssigned;
    static int[] path;
    static int[] resPath;
    static double max=-1;

    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        order=new double[n][n];
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                order[i][j]=in.nextDouble();
            }
        }
        isAssigned=new boolean[n];
        path=new int[n];
        resPath=new int[n];
        dfs(0,path, 0);
        System.out.println(String.format("%.2f", max));
        for(int i=0; i<n; i++){
            System.out.println((i+1)+" "+Math.round(resPath[i]));
        }
    }

    static void dfs(int now, int[] path, double value){
        if(now<path.length){
            for(int i=0; i<path.length; i++){
                if(!isAssigned[i]){
                    path[now]=i+1;
                    isAssigned[i]=true;
                    dfs(now+1, path, value+order[now][i]);
                    isAssigned[i]=false;
                }
            }
        }else{
            if(value>max){
                max=value;
                System.arraycopy(path,0,resPath,0,path.length);
            }
        }
    }
    

}

明天调试一遍;

给出两个字符串,分别是模式串P和目标串T,判断模式串和目标串是否匹配,匹配输出 1,不匹配输出 0。模式串中‘?’可以匹配目标串中的任何字符,模式串中的 ’*’可以匹配目标串中的任何长度的串,模式串的其它字符必须和目标串的字符匹配。例如P=a?b,T=acb,则P 和 T 匹配。

链接:https://www.nowcoder.com/questionTerminal/2e2510b2e41e4d3b922416e51afc077b
来源:牛客网

输入描述:
输入第一行包含一个字符串p, (1 ≤ |p| ≤ 20).

输入第二行包含一个字符串t, (1 ≤ |t| ≤ 20).

输出描述:
输出仅包含0和1的整数,0表示p和t不匹配,1表示p和t匹配。

示例1

输入
a?b
ab
输出
0

示例2
输入

a*b
ab
输出
1

示例3

输入
a*b
a(cb
输出
1

这道题力扣好像有;主要是字符串问题,比起KMP还算简单;

import java.util.*;
public class Main
{
    public static void main(String[] args){
        System.out.print(result());
    }
    public static int result(){
        Scanner sc = new Scanner(System.in);
        String str=sc.nextLine();
        String str2=sc.nextLine();
        char[] strArray=str.toCharArray();
        char[] strArray2=str2.toCharArray();
        int arrayseq=0;
        for(int i=0;i<strArray.length;i++){
            if(strArray[i]=='?'){
                arrayseq++;
                continue;
            }
            else if(strArray[i]=='*'){
                while (true){
                    if (i<strArray.length-1&& strArray[i+1]=='*') {
                        i++;
                    }
                    else {
                        break;
                    }
                }
                if(i==strArray.length-1){
                    return 1;
                }
                else{
 
                    for(int j=arrayseq;j<strArray2.length;j++){
                        if(strArray[i+1]==strArray2[j]){
                            arrayseq=j-1;
                            break;
                        }
                    }
                }
 
            }
            else{
                if(strArray[i]!=strArray2[arrayseq]){
                    return 0;
                }
            }
            arrayseq++;
            if ((i+1)==strArray.length-1&&arrayseq<strArray2.length-1){
                return 0;
            }
            else if (arrayseq==strArray2.length-1&&(i+1)<strArray.length-1){
                return 0;
            }
        }
        return 1;
 
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值