模拟笔试 - 卡码网周赛第二十一期(23年美团笔试真题)

第一题:小美的排列询问 

 

解题思路:
简单题,一次遍历数组,判断  是否有和x、y相等并且相连  即可。

可优化逻辑:因为x和y是后输入的,必须存储整个数组,但是上面说了 **排列是指一个长度为n的数组,其中 1 到 n 每个元素恰好出现一次。**可以充分利用该信息创建一个大小为n+1的数组存储各个元素的所在位置,这样最终直接判断x和y所在位置差是否为1即可判断结果。、

解法一 :哈希表(比较灵活运用哈希表)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        //int[] arr = new int[n];
        //map 记录每个元素所在的位置
        int[] map = new int[n+1];
        for (int i = 0; i < n; i++) {
            int ai = scanner.nextInt();
            map[ai] = i;
        }
        int x = scanner.nextInt();
        int y = scanner.nextInt();

        if(Math.abs(map[x]-map[y])==1){
            System.out.println("Yes");
            return;
        }
        System.out.println("No");
    }
}

Math.abs 是 Java 中 java.lang.Math 类的一个静态方法,用于返回一个数的绝对值。绝对值指的是一个数在数轴上距离原点的距离,因此它始终是非负数。这个方法有多个重载版本,可以处理不同的数据类型,包括 intlongfloat 和 double

 时空复杂度

时间复杂度 :O(n)。一次遍历数组。

空间复杂度 :O(``n``)。哈希表所占空间

解法二:直接模拟(简单粗暴,易想到的方法)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = scanner.nextInt();
        }
        int x = scanner.nextInt();
        int y = scanner.nextInt();

        //遍历数组arr,只有x在前,y在后,或者x在后,y在前的情况满足题意,属于Yes
        for (int i = 0; i < n - 1; i++) {
            if ((arr[i] == x && arr[i + 1] == y) || (arr[i] == y && arr[i + 1] == x)) {
                System.out.println("Yes");
                return;
            }
        }
        System.out.println("No");
    }
}

第二题:小美走公路

解题思路

注意,本题和LeetCode1184.公交站间的距离完全一致。

题目要求计算最短距离,实际上一共只有两条可能的路径:顺时针从x走到y和逆时针从x走到y

因此只需要计算顺时针和逆时针的两个结果进行比较即可。

唯一需要注意的地方就是边界,即第n站到第1站的距离的计算,这里可以通过 逻辑判断 是否到达边界,也可以通过 取余的方式避免边界问题

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取站的数量
        int[] distances = new int[n]; // 存储各站之间的距离
        for (int i = 0; i < n; i++) {
            distances[i] = scanner.nextInt(); // 读取各站之间的距离
        }
        int x = scanner.nextInt(); // 读取出发站
        int y = scanner.nextInt(); // 读取目的站

        int clockwiseDistance = 0; // 顺时针方向的距离
        int counterClockwiseDistance = 0; // 逆时针方向的距离

        // 计算顺时针距离
        // 从出发站到目的站,顺时针方向逐个累加距离
        for (int i = x - 1; i != y - 1; i = (i + 1) % n) {
            clockwiseDistance += distances[i];
        }

        // 计算逆时针距离
        // 从目的站到出发站,逆时针方向逐个累加距离
        for (int i = y - 1; i != x - 1; i = (i + 1) % n) {
            counterClockwiseDistance += distances[i];
        }

        // 输出顺时针和逆时针两种情况下的最短距离
        System.out.println(Math.min(clockwiseDistance, counterClockwiseDistance));
    }
}

 (i + 1) % n : 是一种常见的操作,用于在循环列表(或环形缓冲区、圆形队列)中循环递增索引。这个操作确保了当索引增加到列表的末尾时,它会自动回到开头,从而实现环形访问。这里是详细解释:

  • i:当前的索引。
  • i + 1:下一个索引。
  • % n:取模运算符,n 是列表的长度。

作用

当 i 增加时,(i + 1) 可能会超过数组的最大索引(即 n-1)。为了使索引在超出数组边界时回到起点(形成一个环),使用了取模操作 % n

例如:

  • 当 i 为 0 到 n-2 时,(i + 1) % n 简单地返回 i + 1
  • 当 i 为 n-1(即最后一个元素的索引)时,(i + 1) % n 返回 0,这样就回到了数组的开头。

为了防止顺时针 x到y遇到边界(y在x前时有可能)或者y逆时针走,一定会遇到边界。都需要处理。

 如果用逻辑判断的方法:

这个代码使用逻辑判断来处理数组索引超出边界的情况,使得索引在到达数组边界时正确循环。这样,可以计算两个站之间的最短距离。

// 将站的编号转换为数组的索引(转化为从索引x 到 索引 y) -- 这么操作更方便理解

        int x = scanner.nextInt(); // 读取出发站的编号(假设从1开始)
        int y = scanner.nextInt(); // 读取目的站的编号(假设从1开始)

        // 将站的编号转换为数组的索引(转化为从索引x 到 索引 y)
        x = x - 1;
        y = y - 1;

        int clockwiseDistance = 0; // 初始化顺时针方向的距离
        int counterClockwiseDistance = 0; // 初始化逆时针方向的距离

        // 计算顺时针距离
        // 从出发站开始,按顺时针方向逐个累加距离,
        // 直到到达目的站。通过判断 i == n 确保索引在数组末尾时回到开头。
        int i = x;
        while (i != y) {
            clockwiseDistance += distances[i];
            i++;
            if (i == n) {
                i = 0; // 超出数组末尾,回到开头
            }
        }

        // 计算逆时针距离
        // 从目的站开始,按逆时针方向逐个累加距离,直到回到出发站。
        // 通过判断 i == -1 确保索引在数组开头时回到末尾。
        i = y;
        while (i != x) {
            i--;
            if (i == -1) {
                i = n - 1; // 超出数组开头,回到末尾
            }
            counterClockwiseDistance += distances[i];
        }

力扣解法 :更秒,直接 交换起始地和目的地的位置,再计算相关索引的距离值的和,再比较 

class Solution {
    public int distanceBetweenBusStops(int[] distance, int start, int destination) {
        // 如果start 在 des后面,交换二者
        if (start > destination) {
            int temp = start;
            start = destination;
            destination = temp;
        }
    
        int sum1 = 0, sum2 = 0;
    
        // 遍历整个distance数组
        for (int i = 0; i < distance.length; i++) {
            // 计算从start到destination的总距离
            if (i >= start && i < destination) { //顺时针总距离
                sum1 += distance[i];
            } else { //i < start && i >= destination 逆时针总距离
                // 计算从destination到start的总距离
                sum2 += distance[i];
            }
        }
    
        // 返回从start到destination和从destination到start的距离中较小的值
        return Math.min(sum1, sum2);
    }
}

 第三题:小美的蛋糕切割

第四题:小美的字符串变换

解题思路

这个问题的需求其实是很明确的,根据题意我们需要做两件事

  • 找到所有可以摆列的方式,需要满足x*y=n,假设其中x为小的,那么可以枚举1到k(k*k=n,不需要枚举到n),找到所有的枚举方式
  • 每一个具体的枚举,通过DFS或者BFS的方式,找到其中的联通块数量。具体实现上标记每个位置是否访问,然后从一个方块如果未访问,那么联通块+1然后向四周搜索拓展、标记。
 解法一:DFS
import java.util.*;

public class Main {
    // 方法用于计算最小权值,输入为整数n和字符串s
    public static int minWeight(int n, String s) {
        int minW = Integer.MAX_VALUE; // 初始化最小权值为最大整数值
        
        // 遍历所有可能的矩阵大小,找到所有满足x*y=n的x和y
        for (int i = 1; i * i <= n; i++) {
            if (n % i == 0) {
                int x = i;
                int y = n / i;
                
                // 构建矩阵 (情况1: x为行数,y为列数)
                char[][] matrix = new char[x][y];
                for (int j = 0; j < x; j++) {
                    for (int k = 0; k < y; k++) {
                        matrix[j][k] = s.charAt(j * y + k); // 将字符串s的字符填入矩阵
                    }
                }
                
                // 计算矩阵的权值并更新最小权值
                minW = Math.min(minW, countConnected(matrix));
                
                // 情况2: 交换x和y的位置
                x = n / i;
                y = i;
                
                // 构建矩阵
                matrix = new char[x][y];
                for (int j = 0; j < x; j++) {
                    for (int k = 0; k < y; k++) {
                        matrix[j][k] = s.charAt(j * y + k); // 将字符串s的字符填入矩阵
                    }
                }
                
                // 计算矩阵的权值并更新最小权值
                minW = Math.min(minW, countConnected(matrix));
            }
        }
        return minW; // 返回最小权值
    }

    // 计算矩阵的连通块数量
    public static int countConnected(char[][] matrix) {
        int count = 0; // 初始化连通块计数器
        boolean[][] visited = new boolean[matrix.length][matrix[0].length]; // 记录访问状态的数组
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 四个方向的移动向量

        // 遍历矩阵的每个元素
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                // 如果该位置未被访问
                if (!visited[i][j]) {
                    count++; // 连通块计数加一
                    dfs(matrix, visited, directions, i, j); // 执行深度优先搜索
                }
            }
        }
        return count; // 返回连通块的数量
    }

    // 深度优先搜索连通块
    public static void dfs(char[][] matrix, boolean[][] visited, int[][] directions, int x, int y) {
        visited[x][y] = true; // 标记为已访问,避免重复计算
        // 遍历四个方向
        for (int[] direction : directions) {
            int nx = x + direction[0];
            int ny = y + direction[1];
            // 如果新位置在矩阵范围内且未被访问且与当前字符相同,则递归调用DFS
            if (nx >= 0 && nx < matrix.length && ny >= 0 && ny < matrix[0].length && !visited[nx][ny] && matrix[nx][ny] == matrix[x][y]) {
                dfs(matrix, visited, directions, nx, ny);
            }
        }
    }

    // 主方法
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建Scanner对象以读取输入
        int n = scanner.nextInt(); // 读取整数n
        scanner.nextLine(); // 读取换行符
        String s = scanner.nextLine(); // 读取字符串s
        System.out.println(minWeight(n, s)); // 调用minWeight方法并输出结果
    }
}

第五题:小美的树上染色

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值