2024年美团3.9笔试

题目详情可以参照笔试题目,题解是本人根据网上提供的思路做的,可能会存在问题,仅供参考。前面两题可以在牛客网上测试通过,但第三题会出现超时错误。牛客网站真题

完美矩阵#

小美拿到了一个n*n的矩阵,其中每个元素是 0 或者 1。小美认为一个矩形区域是完美的,当且仅当该区域内 0 的数量恰好等于 1 的数量。现在,小美希望你回答有多少个i*i的完美矩形区域。

关键词:二维前缀和

这题一开始的时候就想着使用1就加一,然后0就减一,最后判断是否为零的方法来判断是否是完美矩阵。但是这就就很复杂了。看别人说是二维前缀和就想到可以统计dp[i][j]是从左上角到ij位置的一的个数,然后判断是否是完美矩阵只需判断1的个数是否是当前矩阵元素个数的一半。读数据的时候当前位置的一的个数等于上方加左边再减去重复部分的1的个数。然后同理也可以指定指定子矩阵的1的个数。说实话这题不算特别难,但是一开始思路错了就没办法了,想不到这个知识点。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] nums = new int[n+1][n+1];
        String str;
        int temp,ans,all;
        //计算前缀和
        for(int i=0;i<n;i++){
            str = in.next();
            for(int j=0;j<n;j++){
                nums[i+1][j+1]=nums[i][j+1]+nums[i+1][j]+(str.charAt(j)-'0')-nums[i][j];
            }
        }

        for(int k=1;k<=n;k++){
            if(k%2!=0){
                System.out.println("0");
                continue;
            }
            ans = 0;
            all = k*k/2;
            for(int i=0;i+k<=n;i++){
                for(int j=0;j+k<=n;j++){
                    temp = nums[i+k][j+k]-nums[i+k][j]-nums[i][j+k]+nums[i][j];
                    if(temp==all) ans++;
                }
            }
            System.out.println(ans);
        }
    }   
}

最多的删除情况#

小美拿到了一个大小为n的数组,她希望删除一个区间后,使得剩余所有元素的乘积末尾至少有k个 0。小美想知道,一共有多少种不同的删除方案?

关键词:数学、前缀和、滑动窗口

这题我只想到了使用前缀和来解决,因此会遇到乘法太大导致溢出的问题,当时还打算使用BigDecimal来解决,原来是自己想的简单了。这题除了前缀和,还考了数学问题,实际上能够得到10的倍数只与2和5的个数相关,其他因子对这个不产生影响。因此我们只需对数组中每个数进行分解,看里面包含多少个2和5,然后用前缀和的方式记录。然后就使用滑动窗口来寻找可以删除的区间。判断条件是这个剩下的区间的2和5的最小值与k进行比较,因为一个2和一个5相乘就是10,那么2和5的最小值就是末尾为零的个数。

import java.util.*;

public class MaxCase {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        long[] pre2 = new long[n+1];
        long[] pre5 = new long[n+1];
        int cnt2,cnt5,temp;

        for(int i=0;i<n;i++){
            temp = in.nextInt();
            cnt2=0;
            cnt5=0;
            for(int x=temp;x%2==0;x/=2) cnt2++;
            for(int x=temp;x%5==0;x/=5) cnt5++;
            pre2[i+1] = pre2[i] + cnt2;
            pre5[i+1] = pre5[i] + cnt5;
        }

        long res = 0;
        for(int i=0,j=0;i<n;i++){
            while(j<n){
                long remain2 = pre2[n] - pre2[j+1] + pre2[i];
                long remain5 = pre5[n] - pre5[j+1] + pre5[i];
                if(Math.min(remain2,remain5)<k) break;
                j++;
            }
            res += Math.max(j-i, 0);
        }

        System.out.println(res);
    }
}

朋友关系#

关键词:并查集、逆序、栈、类、方法重写、集合

这题考到我的智商盲点的,我们需要维护一个并查集来记录朋友关系,这题难点就在于后期会存在遗忘的情况,但是并查集只有合并操作,没有删除操作,由于进行了路径压缩,因此删除的时候难以确定应该修改哪些节点。但是我们可以逆向操作,我们可以逆向遍历查询,遇到删除操作如果是逆序的话则是合并操作,这样就能用并查集进行处理了。确定了大方向后,我们首先读入初始化的边存入数组和集合中,然后存储后期的查询,然后对应后期遗忘的边存入集合方便后续判断。然后才开始初始化关系,注意后期要删除的边不要初始化。然后在存储查询的时候要注意,遗忘中可能包括不是初始化时的操作,是间接关系,是不需要执行并操作的,然后也会出现重复的遗忘,我们要执行加边的是第一次出现的遗忘,因此需要将重复的遗忘从查询中删除。然后要注意重写类的equals方法,传入的参数需要与父类一致,都是Object类,然后hashcode也需要重写,否则集合会判断两者不一样。

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;

public class Relationship {
    static int[] parent;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        int q = in.nextInt();
        int type;

        HashSet<Node> initset = new HashSet<>();//存储初始化的边
        HashSet<Node> deleteSet = new HashSet<>();//存储后期遗忘的边
        Node[] initNodes = new Node[m];
        ArrayList<Node> queryNodes = new ArrayList<>();
        ArrayList<Integer> types = new ArrayList<>();
        Stack<String> ans =new Stack<>();
        Node node;
        parent = new int[n+1];
        for(int i=1;i<=n;i++){
            parent[i] = i;
        }

        for(int i=0;i<m;i++){
            node = new Node(in.nextInt(), in.nextInt());
            initset.add(node);
            initNodes[i] = node;
        }

        for(int i=0;i<q;i++){
            type = in.nextInt();
            node = new Node(in.nextInt(), in.nextInt());

            if(type == 1) {
                if(!deleteSet.contains(node)){//我们只需保留第一个出现的遗忘
                    types.add(type);
                    queryNodes.add(node);
                    deleteSet.add(node);
                }
            }else{
                types.add(type);
                queryNodes.add(node);
            }
        }

        for(int i=0;i<m;i++){
            node = initNodes[i];
            if(!deleteSet.contains(node)){
                union(node.x, node.y);
            }
        }

        for(int i=queryNodes.size()-1;i>=0;i--){
            node = queryNodes.get(i);
            if(types.get(i)==1){
                if(initset.contains(node)){
                    union(node.x, node.y);
                }
            }else{
                if(find(node.x)==find(node.y)){
                    ans.push("Yes");
                }else{
                    ans.push("No");
                }
            }
        }
        
        while(!ans.isEmpty()){
            System.out.println(ans.pop());
        }

        in.close();
    }

    static void union(int i,int j){
        int i_fa = find(i);
        int j_fa = find(j);

        parent[i_fa] = j_fa;
    }

    static int find(int i){
        if(parent[i] == i){
            return i;
        }else{
            parent[i] = find(parent[i]);
            return parent[i];
        }
    }
}

class Node{
    int x;
    int y;

    public Node(int x,int y){
        this.x = x;
        this.y = y;
    }

    //需要传入的是Object类,不然不符合重写的要求
    @Override
    public boolean equals(Object obj){
        Node node = (Node) obj;
        if((x==node.x && y==node.y) || (x==node.y && y==node.x)){
            return true;
        }

        return false;
    }

    //必须重写Hashcode方法,不然会比较为不相同
    public int hashCode(){
        return 1;
    }
}

作者:xiqin

出处:https://www.cnblogs.com/xiqin-huang/p/18063786

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   西芹-小汤圆  阅读(1515)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示