美团2020校招后台开发

1、
给出一个布尔表达式的字符串,比如:true or false and false,表达式只包含true,false,and和or,现在要对这个表达式进行布尔求值,计算结果为真时输出true、为假时输出false,不合法的表达时输出error(比如:true true)。表达式求值是注意and 的优先级比 or 要高,比如:true or false and false,等价于 true or (false and false),计算结果是 true。
解析:and比or的优先级大,一旦遇到and就进行计算,遇到or就再等等,直到最后都是or。可以使用栈,如果当前是操作数true false,就看当前栈是否为空,为空则直接进栈,不为空就看栈的peek是and还是or,and就出栈进行计算,or就进栈。如果当前操作数是and or,判断栈的peek是操作数进栈,否则出错。
当所有都压入栈之后,则进行最后的计算,如果栈非空,且peek为and or则出错,否则如果压出是true则直接为true,如果一直到栈空都没有true出现,则为false。

import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner sc= new Scanner(System.in);
        String str=sc.nextLine();
        String[] s=str.split(" ");
        Stack<String> stack=new Stack<>();
        for(int i=0;i<s.length;i++){
            if(s[i].equals("true")||s[i].equals("false")){
                if(stack.isEmpty()){
                    stack.push(s[i]);
                }else{
                    String pop=stack.peek();
                    if(pop.equals("true")||pop.equals("false")){
                        System.out.println("error");
                        return ;
                    }else{
                        if(pop.equals("or")){
                            stack.push(pop);
                        }else{
                            stack.pop();//and
                            String pre=stack.pop();
                            if(s[i].equals("false")||pre.equals("false")){
                                stack.push("false");
                            }else{
                                stack.push("true");
                            }
                        }
                    }
                }
            }else{//当前是and or
                if(stack.isEmpty()){
                    System.out.println("error");
                    return ;
                }else{
                    String top=stack.peek();
                    if(top.equals("true")||top.equals("false")){
                        stack.push(s[i]);
                    }else{
                        System.out.println("error");
                        return ;
                    }
                }
            }
        }
        if(!stack.isEmpty()&&(stack.peek().equals("or")||stack.peek().equals("and"))){
            System.out.println("error");
            return ;
        }
        //当前栈中可能存在很多操作数和or
        while(!stack.isEmpty()){
            String cur=stack.pop();
            //只要栈中有true,结果就为true
            if(cur.equals("true")){
                System.out.println("true");
                break;
            }
            //如果知道栈空,还没有遇到true,结果就为false
            if(stack.isEmpty()) System.out.println("false");
        }
    }
}

2、
给出两个字符串,分别是模式串P和目标串T,判断模式串和目标串是否匹配,匹配输出 1,不匹配输出 0。模式串中‘?’可以匹配目标串中的任何字符,模式串中的 ’’可以匹配目标串中的任何长度的串,模式串的其它字符必须和目标串的字符匹配。例如P=a?b,T=acb,则P 和 T 匹配。
输入描述:
输入第一行包含一个字符串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

import java.util.Scanner;

public class Main1Test {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String p=sc.nextLine();
        String s=sc.nextLine();
        int m=s.length();
        int n=p.length();
        boolean[][] dp=new boolean[m+1][n+1];
        dp[0][0]=true;
        for(int i=1;i<=n;i++){
            dp[0][i]=dp[0][i-1]&&p.charAt(i-1)=='*';
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='?'){
                    dp[i][j]=dp[i-1][j-1];
                }
                if(p.charAt(j-1)=='*'){
                    dp[i][j]=dp[i-1][j]||dp[i][j-1];
                }
            }
        }
        System.out.println(dp[m][n]?1:0);
    }
}

3、
打车派单场景, 假定有N个订单, 待分配给N个司机。每个订单在匹配司机前,会对候选司机进行打分,打分的结果保存在NN的矩阵A, 其中Aij 代表订单i司机j匹配的分值。 假定每个订单只能派给一位司机,司机只能分配到一个订单。求最终的派单结果,使得匹配的订单和司机的分值累加起来最大,并且所有订单得到分配。
输入描述:
第一行包含一个整数N,2≤N≤10。第二行至第N+1行包含N
N的矩阵。
输出描述:
输出分值累加结果和匹配列表,结果四舍五入保留小数点后两位(注意如果有多组派单方式得到的结果相同,则有限为编号小的司机分配编号小的订单,比如:司机1得到1号单,司机2得到2号单,就比司机1得到2号单,司机2得到1号单要好)
示例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
说明
第一行代表得到的最大分值累加结果5.25,四舍五入保留两位小数;第二行至第四行代表匹配的结果[i j],其中i按行递增:订单1被派给司机2,订单2被派给司机1,订单3被派给司机3。使得A12+ A21+ A33= 1.25 + 1.5 + 2.5 = 5.25在所有的组合中最大。
解析:使用回溯方法,依次遍历每一组的分值,找出最大值,另外在计算每组分值时,将对应的订单和司机也匹配上。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main3 {
     static double max=-1000;
     static boolean[] visited;
     static int n;
     static double[][] nums;
     static List<int[]> relation=new ArrayList<>();
     static List<int[]> maxRelation=new ArrayList<>();
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        nums=new double[n][n];
        visited=new boolean[n];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                nums[i][j]=sc.nextDouble();
            }
        }
        helper(0,0);
        System.out.println(String.format("%.2f",max));
        for(int[] re:maxRelation){
            System.out.println((re[0]+1)+"  "+(re[1]+1));
        }
    }
    public static void helper(int row,double count){
        //每次遍历完一组值时,就计算当前的最大值
        if(row==n){
            if(count>=max){
                if(count==0){
                    max=count;
                    List<int[]> list=new ArrayList<>();
                    for(int i=0;i<n;i++){
                        int[] temp=new int[2];
                        temp[0]=i;
                        temp[1]=i;
                        list.add(temp);
                    }
                    maxRelation=new ArrayList<>(list);
                }else{
                    max=count;
                    maxRelation.clear();
                    maxRelation=new ArrayList<>(relation);
                }
            }
            return ;
        }
        //回溯 递归遍历每组值
        for(int i=0;i<n;i++){
            if(!visited[i]){
                int[] relationArr=new int[2];
                relationArr[0]=row;
                relationArr[1]=i;
                relation.add(relationArr);
                visited[i]=true;
                helper(row+1,count+nums[row][i]);
                relation.remove(relation.size()-1);
                visited[i]=false;
            }
        }
    }
}

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

import java.util.ArrayList;
import java.util.Scanner;

public class Main2 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String str=sc.next();
        ArrayList<Integer> list=new ArrayList<>();
        int maxIndex=0;
        int i=0;
        while(i<str.length()){
            char c=str.charAt(i);
            maxIndex=str.lastIndexOf(c);
            int begin=i;
            i++;
            while(i<=maxIndex){
                char t=str.charAt(i);
                int index=str.lastIndexOf(t);
                if(index>maxIndex) maxIndex=index;
                i++;
            }
            list.add(maxIndex-begin+1);
        }
        for (int j = 0; j < list.size(); j++) {
            System.out.print(list.get(j)+" ");
        }
    }
}

5、
已知一种新的火星文的单词由英文字母(仅小写字母)组成,但是此火星文中的字母先后顺序未知。给出一组非空的火星文单词,且此组单词已经按火星文字典序进行好了排序(从小到大),请推断出此火星文中的字母先后顺序。
输入描述:
一行文本,为一组按火星文字典序排序好的单词(单词两端无引号),单词之间通过空格隔开
输出描述:
按火星文字母顺序输出出现过的字母,字母之间无其他字符,如果无法确定顺序或者无合理的字母排序可能,请输出"invalid"(无需引号)
示例1
输入
z x
输出
zx
示例2
输入
wrt wrf er ett rftt
输出
wertf
示例3
输入
z x z
输出
invalid
解析:首先是按照字母的顺序逐一加入到set中,然后每一个字符串和其后面的字符串相比,如果两个字母不同且之前没有同时出现,且将其放入到map中(map中保存每个字符和每个字符之间的路线),所有字母形成一个图之后,判断如果有超过一个的字母的入度为0,则说明会存在无法确认的情况,如果产生了闭环,就是说没有入度为0的字母则也会出现无法确认的情况。
找到顺序就是:首先找到入度为0的字母,然后将其与之相连的路都断掉,再次查找入度为0的字母。

import java.util.*;

/**
 * 给定按火星字典序排列的单词,求单词中出现过的字符的字典序
 * wrt wrf er ett rftt
 * x z x
 * abc bbc
 * hij ikjk kih jkca jkaa jj
 * 构造一个字符的有向无环图,再找拓扑序列
 */
public class Main4 {
    // 保存图,定义如果字符i在字符j前,那么存在i到j路径,即map[i][j]=1
    private static int[][] map = new int[26][26];
    // 保存每个节点的入度
    private static int[] indegree = new int[26];
    // 记录出现过的字符
    private static boolean[] flag = new boolean[26];
    private static Set<Character> set = new HashSet<>();
    // 保存结果
    private static List<Character> ans = new ArrayList<>();

    public static void main(String[] args) {
        // wrt wrf er ett rftt
        Scanner sc = new Scanner(System.in);
        String[] input = sc.nextLine().split(" ");
        int maxLen = 0;
        // 创建有向图
        build(input);
        // 找拓扑序列
        topology();
        if(ans.size() == set.size()) {
            for (Character c : ans) {
                System.out.print(c);
            }
        } else {
            System.out.println("invalid");
        }
    }

    public static void topology() {
        while(ans.size() < set.size()) {
            // 是否在一个遍历中找到入度为0的节点,如果没找到,要break;如果一次遍历找到两个入度为0的点,说明是无法确认顺序的
            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]) {
                    ans.add((char) ('a' + i));
                    flag[i] = false;    // 删除节点
                    for (int j = 0; j < 26; j++) {       // 删除从这个节点出发的边
                        if (map[i][j] == 0) continue;
                        indegree[j]--;
                        map[i][j] = 0;
                    }
                }
            }
        }
    }


    //[wrt wrf er ett rftt]
    public static void build(String[] strs) {
        // 找到相邻的两个字符串,第一个不相同的字符可以确定字符的顺序
        // 如wrt和wrf可以得到:t->f
        String pre = strs[0];
        for (char c : pre.toCharArray()) {
            set.add(c);
        }
        for(int i = 1; i < strs.length; i++) {
            String cur = strs[i];
            for (char c : cur.toCharArray()) {
                set.add(c);
            }
            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;
                indegree[cur.charAt(j)-'a'] += 1;
                flag[pre.charAt(j)-'a'] = true;
                flag[cur.charAt(j)-'a'] = true;
                break;
            }
            pre = cur;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值