【牛客】【刷题节】美团2024届秋招笔试第一场编程真题

1.小美的外卖订单【简单题】

题意理解:

        这道题是简单题,主要是一个逻辑实现和判断的问题。但是简单题一般喜欢加一点小障碍,所以读题的时候就要比较注意一些约束条件。就比如这道题:过了15/20个测试用例,出现error, 当时没明白到底哪里校验有问题,最后发现: 原价、折扣、满减都是正实数。所谓正实数:没有0!!!

        正实数:是实数(real numbers)中的一个重要概念,它们是大于0的所有实数。正实数包括正整数、正分数(即正小数)以及正无理数

        还涉及一些边边角角的考核: 小数点保留两位

解题思路:

        1.计算每道菜的折扣价 原价-折扣价,注意约束条件判断:原价>=折扣价>0

        2.统计所有菜原价sum1

        3.统计所有菜折扣价sum2

        4.判断原价是否满足满减     sum1>=满减>0,并返回满减后的价格给sum1

        5.返回最优惠min(sum1,sum2)

1.题目实现

import java.text.DecimalFormat;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        double[][] prices = new double[n][2];
        for (int i = 0; i < n; i++) {
            prices[i][0] = in.nextDouble();
            prices[i][1] = in.nextDouble();
        }
        double x = in.nextDouble();
        double y = in.nextDouble();
        System.out.println(main.compute(prices, x, y));
    }

    public String compute(double[][] prices, double x, double y) {
        if (x==0||y==0||x < y|| y<0) return "error";
        double cost1 = 0.0;
        double cost2 = 0.0;
        for (int i = 0; i < prices.length; i++) {
            if(prices[i][0]==0||prices[i][0]==0) return "error";
            if (prices[i][0] >= prices[i][1]&&prices[i][1]>0) {
                cost1 += prices[i][0];
                cost2 += prices[i][1];
            } else {
                return "error";
            }
        }
        double minCost = cost2;
        //满减否
        if (cost1 >= x) { //满足满减条件
            minCost = Math.min(minCost, cost1 - y);
        }
        DecimalFormat df = new DecimalFormat("#.00");
        return df.format(minCost);
    }
}

2.复杂度分析

时间复杂度:O(n) 遍历菜的时间损耗

空间复杂度:O(n)  存储菜的空间损耗

2.小美的字符串匹配度【不难,但题看错了气死!】

题意理解

       这道题想复杂了,原因是题没读明白,所以读题真的太重要了!!!

        这题给定两个字符串,从头开始往后匹配

        对于字符串可以操作一次两个元素换位置,最多操作一次,可以不操作

        最终,我们能获得的最大匹配是多少?

解题思路

        实现:借鉴大佬思路

        遍历s和t,将对应位置上匹配到的元素剔除,删除后,上下元素坐标一致且值不同

        如:"abacd"和"aabdd“  操作完 ”bca“ 和”abd“

        bac和abd中,遍历s: bac ,若取到b,i=0;

        在t:abd中找可以匹配的b ,如j=1时,匹配

        此时有个需要额外注意的点:

                s[i]=b ==  t[j]==b  将t串,i|j位置互换,在i位置上获得一个匹配,+1

                额外的判断: s[j]==t[i]  交换后,对应的j位置是否能再次获得一个匹配呢?

1.题目实现

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        String s1 = in.nextLine();
        String s2 = in.nextLine();
        System.out.println(main.compute(s1, s2));
    }

    public int compute(String s1, String s2) {
        int pairs = 0;
        int len = s1.length(); //s1和s2等长
        StringBuilder sb1 = new StringBuilder(s1);
        StringBuilder sb2 = new StringBuilder(s2);
        //在s2中找s1的匹配
        for (int i = 0; i < len; i++) {
            if (sb1.charAt(i) == sb2.charAt(i)) {
                sb1.deleteCharAt(i);
                sb2.deleteCharAt(i);
                i--;//第i个被删除后,回溯到前一个
                len--;
                pairs++;
            }
        }
        len = sb1.length();
        int changePairs = 0;
        for (int i = 0; i < len; i++) {
            for (int j = i; j < len; j++) {
                if (sb1.charAt(i) == sb2.charAt(j) || sb1.charAt(i) == sb2.charAt(j)) {
                    changePairs = Math.max(1, changePairs);
                } 
                if (sb1.charAt(i) == sb2.charAt(j) && sb1.charAt(j) == sb2.charAt(i)) {
                    changePairs = 2;
                    break;//最多增加两个匹配,不会再多了,所以可以退出了
                }
            }
        }
        return pairs+changePairs;
    }
}

2.复杂度分析

时间复杂度:O(n^2) 双for时间损耗

空间复杂度:O(2n)  两字符串长度空间损耗

3.小美的树上染色【有难度,但是很大原因是题看错了】

题意理解:

        按照要求对节点染色,要求染色的节点最多。

        相邻为染色且和为平方数的两节点染色。

        这道题目是:一定要染红嘛?想复杂了,如果可以染色,一定要染。然后这道题变成了简单题。一定要仔细看题看题。

        看了大佬解题思路有个地方不明白,为什么要从后往前遍历边呢?

        反着测试用例过不去,不理解!有懂得大佬能给我讲讲嘛~

解题思路:

       1.遍历所有的边,判断两节点是否满足染色要求:相邻为染色且和为平方数的两节点染色。

        2.符合条件:两节点染色,sum+=2

 1.题目实现

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Main solution=new Main();
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        int[][] node=new int[n][2];
        for(int i=0;i<n;i++){
            node[i][0]=in.nextInt();
            node[i][1]=0;
        }
        int[][] lines=new int[n-1][2];
        for(int i=0;i<n-1;i++){
            lines[i][0]=in.nextInt()-1;
            lines[i][1]=in.nextInt()-1;
        }
        System.out.println(solution.compute(n,node,lines));
    }

    /**
     * 计算染色节点
     * @param n 节点个数
     * @param node  0是权值,1是颜色;(0白色1红色)
     * @param lines 边关系
     * @return
     */
    public int compute(int n,int[][] node,int[][] lines){
        int result=0;
        for(int i=lines.length-1;i>=0;i--){
            //两个相邻白色节点
            if(node[lines[i][0]][1]==0&&node[lines[i][1]][1]==0){
                //是平方数
                float product=node[lines[i][0]][0]*node[lines[i][1]][0];
                if(Math.sqrt(product)-(int)Math.sqrt(product)==0){
                    node[lines[i][0]][1]=1;
                    node[lines[i][1]][1]=1;
                    result+=2;
                }
            }
        }
        return result;
    }
}

2.复杂度分析

时间复杂度:  O(n)遍历边

空间复杂度:O(n^2) 边、节点的存储

4.小美的排列询问【简单题】

题意理解

        遍历数组,查看给出的元素是否相邻即可

解题思路

        1.遍历数组,找到其中一个元素

        2.查看另一个元素是否在该元素的左|右

        3.若在Yes

        4.不在则下一个,遍历完都找不到,No

1.题目实现

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = in.nextInt();
        }
        int x = in.nextInt();
        int y = in.nextInt();
        System.out.println(main.compute(nums, x, y));
    }
    public String compute(int[] nums, int x, int y) {
        int a = Math.min(x, y);
        int b = Math.max(x, y);
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] == a && ((i + 1) < nums.length && nums[i + 1] == b || i - 1 >= 0 &&
                                 nums[i - 1] == b)) return "Yes";
            else if (nums[i] == a && !((i + 1) < nums.length && nums[i + 1] == b ||
                                       i - 1 >= 0 && nums[i - 1] == b)) return "No";
        }
        return "No";
    }
}

2.复杂度分析

时间复杂度:O(n) 遍历数组的时间损耗

空间复杂度:O(n) 数组存储的空间损耗

5.小美的排列构造【这也是道简单题】

题意理解:

        首先明确:数组权值:对相邻两项求和,其中最大值和最小值的差值

        为了绕让权值尽可能的小

        就要使相临两数之间的和差不多的大。

        一个思路是:首先对数组进行排序。

        从数组末尾取数据,往数组前面的元素间插入,总是一个小值,一个大值的。

        但是测试没过,不知道哪里的问题。——错在了,奇数个元素时,漏了一个元素

解题思路:

        

1.题目实现

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        System.out.println(main.compute(n));
    }
    public String compute(int n){
        StringBuilder sb=new StringBuilder();
        for(int i=1;i<=n/2;i++){
            sb.append(i+" "+(n-i+1)+" ");
        }
        if(n%2!=0){
            sb.append((n+1)/2);
        }
        return sb.toString();
    }
}

2.复杂度分析

特别有意思的一点:【记录一下】

        用String result+""拼接字符串,超时了

        但是用StringBulider是可以的

时间复杂度:O(n/2)遍历一半数据的时间损耗

空间复杂度:O(n)存储数据的空间损耗

6.小美走公路【简单题】

题意理解:

        由于是环形公路,所有从x到y站无非两种方式:顺时针|逆时针

        可以统计全程sum,和x到y的顺时针长度len1,则逆时针sum-len1

解题思路:

        1.遍历所有的站点到下一站距离

        2.统计全程长度sum

        3.当遍历到x站点开始统计长度len1,到站点y结束

        4.返回min(sum-le1,len1)

1.题目实现

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main=new Main();
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        long[] a=new long[n];
        for(int i=0;i<n;i++){
            a[i]=in.nextLong();
        }
        long x=in.nextLong();
        long y=in.nextLong();
        System.out.println(main.compute(a,x,y));
    }
    public long compute(long[] a,long x,long y){
        long start=Math.min(x,y);
        long end=Math.max(x,y);
        long sum=0;//整圈
        long left=0;//从start->end
        for(int i=0;i<a.length;i++){
            if(i>=start-1&&i<end-1) left+=a[i];
            sum+=a[i];
        }
        return Math.min(left,sum-left);
    }
}

2.复杂度分析

时间复杂度分析:O(n) 遍历站点的时间损耗

空间复杂度分析:O(n) 站点存储的时间损耗

7.小美的好矩阵【感觉自己思路没错,但是测试用例没过】

 

题意理解:

        在n*m的矩阵中找到一个符合好矩阵的条件矩阵。有多少个?

解题思路:        

        row[i][j]:第i行,第j个位置,构造一个行,是否满足好矩阵一个行的条件:true|false

        思路是这样的,首先对每行的每个位置开始,构造一个行,判断其是否符合好矩阵的行。

        contains[i][j][k]:第i行,第j个位置,构造一个行,包含ABC的个数:k=0:A,k=1:B,k=3:C

        col[i][j]:第i列,第j个位置,构造一个列,是否满足好矩阵一个列的条件:true|false

        对每列的每个位置开始,构造一个列,判断其是否符合好矩阵的列。

1.题目实现

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main=new Main();
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        int m=in.nextInt();
        in.nextLine();
        char[][] map=new char[n][m];
        for(int i=0;i<n;i++){
            map[i]=in.nextLine().toCharArray();
        }
        System.out.println(main.compute(map,n,m));
    }

    public int compute(char[][] map,int n,int m) {
        boolean[][] row = new boolean[n][m];
        boolean[][] col = new boolean[n][m];
        boolean[][][] contains=new boolean[n][m][3];
        Deque<int[]> queue = new LinkedList<>();
        //初始化:行检测
        for (int i = 0; i < n; i++) {//行检测
            for (int j = 0; j < m; j++) {
                if (queue.size() == 3) {
                    queue.pollFirst();
                }
                if ("ABC".contains(Character.toString(map[i][j]))) {
                    if(!queue.isEmpty()){
                        int pre_i = queue.peekLast()[0], pre_j = queue.peekLast()[1];
                        if (map[pre_i][pre_j] == map[i][j]) {//与前一个重复,丢弃前面的
                            queue.clear();
                        }
                    }
                    queue.offerLast(new int[]{i, j});//加入最新元素
                    if (queue.size() == 3) {
                        row[i][j] = true;//当前及前两个构成一个结果
                        if(map[i][j]=='A'||map[i][j-1]=='A'||map[i][j-2]=='A') contains[i][j][0]=true;
                        if(map[i][j]=='B'||map[i][j-1]=='B'||map[i][j-2]=='B') contains[i][j][1]=true;
                        if(map[i][j]=='C'||map[i][j-1]=='C'||map[i][j-2]=='C') contains[i][j][2]=true;
                    }

                } else {
                    queue.clear();
                }
            }
            queue.clear();
        }
        queue.clear();
        //初始化:列检测
        for (int j = 0; j < m; j++) { //列检测
            for (int i = 0; i < n; i++) {
                if (queue.size() == 3) {
                    queue.pollFirst();
                }
                if ("ABC".contains(Character.toString(map[i][j]))) {
                    if(!queue.isEmpty()){
                        int pre_i = queue.peekLast()[0], pre_j = queue.peekLast()[1];
                        if (map[pre_i][pre_j] == map[i][j]) {//与前一个重复,丢弃前面的
                            queue.clear();
                        }
                    }
                    queue.offerLast(new int[]{i, j});//加入最新元素
                    if (queue.size() == 3) {
                        col[i][j] = true;//当前及前两个构成一个结果
                    }

                } else {
                    queue.clear();
                }
            }
            queue.clear();
        }
        //九宫格检查
        int result = 0;
        for (int i = 2; i < n; i++) {
            for (int j = 2; j < m; j++) {
                //矩阵里有没有ABC:查三行元素
                //containsC[i][j]||containsC[i-1][j]||containsC[i-2][j])
                //三行检测:倒着数三行
                //row[i][j]&&row[i-1][j]&&row[i-2][j]
                //三列检测:倒着数三行
                //col[i][j]&&col[i][j-1]&&col[i][j-2]
                if ((contains[i][j][0]||contains[i-1][j][0]||contains[i-2][j][0])&&//有A
                        (contains[i][j][1]||contains[i-1][j][1]||contains[i-2][j][1])&&//有B
                        (contains[i][j][2]||contains[i-1][j][2]||contains[i-2][j][2])&&//有C
                        row[i][j] && row[i - 1][j] && row[i - 2][j] &&
                                col[i][j] && col[i][j - 1] && col[i][j - 2]) {
                    result++;
                }

            }
        }
        return result;
    }
}

2.复杂度分析

时间复杂度:O(n*m)  双for的时间损耗

空间复杂度:O(n*m*3)   contains的空间损耗

这道题主要难在了判断和分析上,要做到准确且不漏

8.小美的蛋糕切割【简单题】

题意理解:

        切蛋糕,这里把蛋糕看成n*m个小格子组成的整体,不能把小格子切开,所以切蛋糕的位置就是(n+m),切开之后,美味度是每部分小格子权值和

解题思路:

        1.遍历横切n个位置,求每次的最小美味度差值

        2.遍历竖切m个位置,求每次的最小美味度差值

        3.返回最小美味度差值(此处差值求绝对值)

1.题目实现

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main=new Main();
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        int[][] cake=new int[n][m];
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cake[i][j]=in.nextInt();
            }
        }
        System.out.println(main.compute(cake,n,m));
    }

    public int compute(int[][] cake,int n,int m){
        long[] row=new long[n];
        long[] col=new long[m];
        long sum=0;
        long minResult=Integer.MAX_VALUE;
        //行计数+总和计数
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                row[i]+=cake[i][j];
            }
            sum+=row[i];
        }
        //列计数
        for(int j=0;j<m;j++){
            for(int i=0;i<n;i++){
                col[j]+=cake[i][j];
            }
        }
        //遍历横刀切
        long cake1=0,cake2=0;
        for(int i=0;i<=n-1;i++){
            cake1+=row[i];
            cake2=sum-cake1;
            minResult=Math.min(minResult,Math.abs(cake1-cake2));
        }
        //遍历横刀切
        cake1=0;cake2=0;
        for(int j=0;j<=m-1;j++){
            cake1+=col[j];
            cake2=sum-cake1;
            minResult=Math.min(minResult,Math.abs(cake1-cake2));
        }
        return (int)minResult;
    }
}

2.复杂度分析

时间复杂度:O(n^2) 双for循环损耗

空间复杂度:O(n^2)  cake数组空间损耗

9.小美的字符串变换【困难:图相关的没复习】

题意理解

        看大佬的做法,这是dfs,深度遍历,但是emmmm,图论没有好好复习哎。

        借鉴了下大佬思路,其实不难。就是递归遍历图,和遍历树是一样的。只是这里借助一个uesd存储访问状态。

解题思路

        将字符串n铺成一个矩阵

        该矩阵的权值:连通块数

        欲求最小的连通块数。

        1.遍历所有可能的矩阵组合,即n%i==0

        2.在每一个可能的矩阵组合中,统计联通图个数。

        3.统计连通图个数用count来维护,dfs(map, used, x, y, ++count);

           每找到一个连通图,count++(同一块,count相同)

        如:矩阵:aababbabb     used中的count: [1, 1, 2, 3, 4, 4, 5, 6, 6]

1.解题思路

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        String input = in.nextLine();
        
        Main main = new Main();
        System.out.println(main.compute(n, input));
    }
    
    public int compute(int n, String s) {
        int res = Integer.MAX_VALUE;
        for (int i = 1; i <= n; i++) {
            if (n % i == 0) { //摆阵

                char[][] map = new char[i][n / i];
                int[][] used = new int[i][n / i];
                //赋值
                int index = 0;
                for (int x = 0; x < i; x++) {
                    for (int y = 0; y < n / i; y++) {
                        map[x][y] = s.charAt(index++);
                    }
                }
                //dfs计算联通图树
                //赋值
                int count = 0;
                for (int x = 0; x < i; x++) {
                    for (int y = 0; y < n / i; y++) {
                        //寻找每一个
                        if (used[x][y] == 0) {
                            dfs(map, used, x, y, ++count);
                        }
                    }
                }
                res = Math.min(res, count);

            }
        }
        return res;
    }

    public void dfs(char[][] map, int[][] used, int i, int j, int count) {
        /**
         * i,j越界或该位置已被访问过
         */
        if (i < 0 || j < 0 || i > map.length - 1 || j > map[0].length - 1 ||
                used[i][j] != 0) return;
        used[i][j] = count;
        /**
         * 像四个位置尝试扩展
         */
        if (i > 0 && map[i][j] == map[i - 1][j]) {
            dfs(map, used, i - 1, j, count);
        }
        if (i < map.length - 1 && map[i][j] == map[i + 1][j]) {
            dfs(map, used, i + 1, j, count);
        }
        if (j > 0 && map[i][j] == map[i][j - 1]) {
            dfs(map, used, i, j - 1, count);
        }
        if (j < map[0].length - 1 && map[i][j] == map[i][j + 1]) {
            dfs(map, used, i, j + 1, count);
        }
    }
}

2.复杂度分析

时间复杂度:O(n^3)  矩阵构建的时间耗费(O(n^2))*dfs的时间耗费(dfs,查联通分量每个节点访问一次,总的是O(n))

空间复杂度:O(n^2) uesd及map的空间耗费

  • 31
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值