第十五届蓝桥杯模拟赛(第一期)

大家好,我是晴天学长,本次分享,制作不易,需要的小伙伴可以点赞关注评论一波哦!后续会继续更新第二期第三期的。💪💪💪

一 .找数位


问题描述
 请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。
  请将这个数的十进制形式作为答案提交。
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

1) .算法思路

  • 发现输出的过程中,最小的只有aaa,所以就是2730。

2).算法步骤

1.初始化变量 n 为 2022,将变量 watch 设置为 true。

2.进入一个无限循环。

3.将变量 n 转换为十六进制字符串,并存储在变量 s 中。

4.遍历 s 中的每个字符。

5.如果字符是一个数字(介于 ‘0’ 和 ‘9’ 之间的字符),将 watch 设置为 false,表示条件不满足。

6.循环结束后,检查 watch 的值。

7.如果 watch 仍然为 true,则说明十六进制字符串中的所有字符都是字母(非数字)。

8.打印十六进制字符串 s 和对应的十进制值 n。

9.跳出循环。

10.如果条件不满足,将 n 的值增加 1。

11.回到步骤 3,继续下一次循环。

12.当找到满足条件的最小数时,程序终止。

3). 代码实例

package LeetCodeTest.枚举;

import java.util.Scanner;

public class 最小数 {
    public static void main(String[] args) {
//        int t = Integer.parseInt("aaa",16);
//        System.out.println(t);
        Scanner scanner = new Scanner(System.in);
        int n = 2022;
        boolean watch = true;
        while (true) {
            watch = true;
            String s = Integer.toString(n, 16);
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if ('0' <= c && c <= '9') {
                    watch = false;
                    break;
                }
            }
            if (watch == true){
                System.out.println(s);
                System.out.println(n);
                break;
            }
            n++;
        }
    }
}

4).总结
  • 答案:2730

二 . Excel2022


问题描述
  在 Excel 中,列的名称使用英文字母的组合。前 26 列用一个字母,依次为 A 到 Z,接下来 26*26 列使用两个字母的组合,依次为 AA 到 ZZ。
  请问第 2022 列的名称是什么?
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。

1) .算法思路

2).算法步骤

3). 代码实例

  • Excel。
  • 手算。

4).总结

  • 答案:BYT

三 .数字之和


问题描述
 对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1 日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。
 例如,2022年11月13日满足要求,因为 2+0+2+2=(1+1)+(1+3) 。
  请提交满足条件的日期的总数量。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

1) .算法思路

  • 日期模拟+简单的条件判断。

2).算法步骤

1.定义了一个静态数组 w,用于存储每个月份的天数。

2.初始化年份 y 为 1900,月份 m 为 1,日期 d 为 1。

3.初始化计数器变量 ans 为 0。

4.进入一个循环,直到日期等于 9999 年 12 月 31 日为止。

5.在循环中,首先根据闰年的规则判断二月份的天数。

6.调用 check 方法检查日期是否满足条件。如果满足条件,则将计数器 ans 增加 1。

7.将日期 d 增加 1。

8.如果日期超过了当前月份的天数,则将月份 m 增加 1,日期重置为 1。

9.如果月份超过了 12,则将月份重置为 1,年份 y 增加 1。

10.循环回到第 4 步,继续下一次循环。

11.当日期等于 9999 年 12 月 31 日时,退出循环。

12.最后再次调用 check 方法检查最后一个日期是否满足条件,如果满足条件,则将计数器 ans 增加 1。

13.打印计数器 ans 的值。

14.check 方法用于检查年份和日期的各位数字之和是否相等。

15.在 check 方法中,分别计算年份和日期的各位数字之和,并将结果存储在变量 ans 和 sum 中。

16.如果年份的各位数字之和等于 sum,则返回 true,否则返回 false。

3). 代码实例

package LanQiaoTest.时间模拟;

public class 年月日数位之和 {
    static int[] w = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    static int y = 1900, m = 1, d = 1;

    public static void main(String[] args) {
        int ans = 0;
        while (y != 9999 || m != 12 | d != 31) {
            if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) w[2] = 29;
            else w[2] = 28;
            if (check()) ans++;
            d++;
            if (d > w[m]) {
                m++;
                d = 1;
            }
            if (m > 12) {
                m = 1;
                y++;
            }
        }
        if (check()) ans++;
        System.out.println(ans);
    }

    static boolean check() {
        int ans = 0;
        int sum = 0;
        // 计算年的和
        int a = y;
        while (a > 0) {
            ans += a % 10;
            a /= 10;
        }
        int b = m;
        int c = d;
        while (b > 0) {
            sum += b % 10;
            b /= 10;
        }
        while (c > 0) {
            sum += c % 10;
            c /= 10;
        }
        return ans==sum;
    }
}

4).总结

  • 答案:70910。

四 .435种取法

问题描述
  小蓝有 30 个数,分别为:99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77 。
  小蓝可以在这些数中取出两个序号不同的数,共有 30*29/2=435 种取法。
  请问这 435 种取法中,有多少种取法取出的两个数的乘积大于等于 2022 。 答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

1) .算法思路

  • 数据量小,暴力枚举,当然有兴趣的小伙伴试试,枚举二分会更快。

2).算法步骤

1.初始化计数器变量 ans 为 0。

2.定义一个整数数组 nums,其中包含了一组数字。

3.使用两个嵌套的循环遍历数组中的每一对数字。

4.外层循环控制第一个数字的索引,从 0 开始,到 nums.length – 2 结束。

5.内层循环控制第二个数字的索引,从外层循环的下一个索引开始,即 i + 1,到 nums.length – 1 结束。

6.在循环中,判断两个数字的乘积是否大于等于 2022。如果满足条件,则将计数器 ans 增加 1。

7.循环结束后,打印计数器 ans 的值。

3). 代码实例

package LanQiaoTest.枚举;

public class 取法 {
    public static void main(String[] args) {
        int ans = 0;
        int[] nums = {
                99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77};
        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i]*nums[j]>=2022){
                    ans++;
                }
            }
        }
        System.out.println(ans);
    }
}

4).总结

  • 答案:189。

五 . 最大连通分块


问题描述
小蓝有一个 30 行 60 列的数字矩阵,矩阵中的每个数都是 0 或 1 。
  110010000011111110101001001001101010111011011011101001111110
  010000000001010001101100000010010110001111100010101100011110
  001011101000100011111111111010000010010101010111001000010100
  101100001101011101101011011001000110111111010000000110110000
  010101100100010000111000100111100110001110111101010011001011
  010011011010011110111101111001001001010111110001101000100011
  101001011000110100001101011000000110110110100100110111101011
  101111000000101000111001100010110000100110001001000101011001
  001110111010001011110000001111100001010101001110011010101110
  001010101000110001011111001010111111100110000011011111101010
  011111100011001110100101001011110011000101011000100111001011
  011010001101011110011011111010111110010100101000110111010110
  001110000111100100101110001011101010001100010111110111011011
  111100001000001100010110101100111001001111100100110000001101
  001110010000000111011110000011000010101000111000000110101101
  100100011101011111001101001010011111110010111101000010000111
  110010100110101100001101111101010011000110101100000110001010
  110101101100001110000100010001001010100010110100100001000011
  100100000100001101010101001101000101101000000101111110001010
  101101011010101000111110110000110100000010011111111100110010
  101111000100000100011000010001011111001010010001010110001010
  001010001110101010000100010011101001010101101101010111100101
  001111110000101100010111111100000100101010000001011101100001
  101011110010000010010110000100001010011111100011011000110010
  011110010100011101100101111101000001011100001011010001110011
  000101000101000010010010110111000010101111001101100110011100
  100011100110011111000110011001111100001110110111001001000111
  111011000110001000110111011001011110010010010110101000011111
  011110011110110110011011001011010000100100101010110000010011
  010011110011100101010101111010001001001111101111101110011101
  如果从一个标为 1 的位置可以通过上下左右走到另一个标为 1 的位置,则称两个位置连通。与某一个标为 1 的位置连通的所有位置(包括自己)组成一个连通分块。
  请问矩阵中最大的连通分块有多大?

1) .算法思路

  • 简单的bfs暴力枚举。

2).算法步骤

1.定义了两个数组 dx 和 dy,用于表示四个方向的位移:上、下、左、右。

2.使用 BufferedReader 读取输入。

3.定义一个二维数组 G,用于存储输入的矩阵。

4.使用嵌套的循环遍历整个矩阵,将输入的字符转换为对应的数字,并存储在数组 G 中。

5.初始化变量 max 为 0,用于记录最大的连通分快的大小。

6.再次使用嵌套的循环遍历整个矩阵。

7.如果当前位置的值为 1,表示是一个连通分快的起始位置。

8.创建一个二维布尔数组 st,用于标记已访问的位置。

9.使用 bfs 方法进行广度优先搜索,返回连通分快的大小,并更新 max 的值。

10.循环结束后,打印 max 的值,即最大的连通分快的大小。

11.在 bfs 方法中,初始化连通分快的大小 ans 为 1,表示当前位置已经被访问。

12.将当前位置标记为已访问。

13.创建一个队列 queue,将当前位置加入队列。

14.进入一个循环,直到队列为空。

15.获取当前队列的大小,表示当前步数可以访问的位置个数。

16.在内层循环中,依次处理队列中的每个位置。

17.获取当前位置的坐标。

18.遍历四个方向的位移,计算新的坐标。

19.如果新坐标在合法范围内,且对应位置的值为 1,并且未被访问过,则将新位置标记为已访问,加入队列,并将 ans 的值加1。

20.循环结束后,返回连通分快的大小 ans。

3). 代码实例

package LanQiaoTest.BFS;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;

public class 最大的连通分快 {
    //遍位移
    static int[] dx = {0, 0, -1, 1};
    static int[] dy = {-1, 1, 0, 0};

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] s;
        int[][] G = new int[30][60];
        //接受矩阵
        for (int i = 0; i < 30; i++) {
            s = in.readLine().split("");
            for (int j = 0; j < 60; j++) {

                G[i][j] = Integer.parseInt(s[j]);
            }
        }
        int max = 0;
        //遍历矩阵
        for (int i = 0; i < 30; i++) {
            for (int j = 0; j < 60; j++) {
                if (G[i][j] == 1) {
                    boolean[][] st = new boolean[30][60];
                    max = Math.max(max, bfs(i, j, st, G));
                }

            }
        }

        System.out.println(max);
    }

    private static int bfs(int x, int y, boolean[][] st, int[][] G) {
        int ans = 1;
        st[x][y] = true;
        Queue<int[]> queue = new LinkedList<>();
        //放入数据
        queue.offer(new int[]{x, y});
        while (!queue.isEmpty()) {
            //一步有几个
            int size = queue.size();
            while (size-- > 0) {
                int[] curr = queue.poll();
                int a = curr[0];
                int b = curr[1];
                //开枝散叶
                for (int i = 0; i < 4; i++) {
                    int newX = a + dx[i];
                    int newY = b + dy[i];
                    if (newX >= 0 && newX < 30 && newY >= 0 && newY < 60 && G[newX][newY] == 1 && st[newX][newY] == false) {
                        st[newX][newY] = true;
                        queue.offer(new int[]{newX, newY});
                        ans++;
                    }
                }
            }
        }
        return ans;
    }
}

4).总结

  • 答案:148.

六 .那一天?


问题描述
  给定一天是一周中的哪天,请问 n 天后是一周中的哪天?
输入格式
  输入第一行包含一个整数 w,表示给定的天是一周中的哪天,w 为 1 到 6 分别表示周一到周六,w 为 7 表示周日。
  第二行包含一个整数 n。
输出格式
  输出一行包含一个整数,表示 n 天后是一周中的哪天,1 到 6 分别表示周一到周六,7 表示周日。
样例输入
6
10
样例输出
2
评测用例规模与约定
  对于所有评测用例,1 <= n <= 1000000。

1) .算法思路

  • 星期的取余操作,这个可以很好的控制范围。

2).算法步骤

1.使用Scanner对象的nextInt方法从用户那里读取两个整数a和b。
2.计算a和b的和的模7,并将结果存储在变量answer中:(a + b % 7) % 7。
3 .使用if语句检查answer是否等于0。如果为真,表示结果可以被7整除,所以使用4.System.out.println(7)打印出7。
5.如果if条件为假,表示结果不能被7整除,所以使用System.out.println(answer)打印出计算得到的结果。

3). 代码实例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int a = scanner.nextInt();
        int b = scanner.nextInt();
        int answer = (a + b % 7) % 7;
        if (answer == 0) {
            System.out.println(7);
        } else {
            System.out.println(answer);
        }
    }
}

4).总结

七 .信号塔

问题描述
  小蓝负责一块区域的信号塔安装,整块区域是一个长方形区域,建立坐标轴后,西南角坐标为 (0, 0), 东南角坐标为 (W, 0), 西北角坐标为 (0, H), 东北角坐标为 (W, H)。其中 W, H 都是整数。
  他在 n 个位置设置了信号塔,每个信号塔可以覆盖以自己为圆心,半径为 R 的圆形(包括边缘)。
  为了对信号覆盖的情况进行检查,小蓝打算在区域内的所有横纵坐标为整数的点进行测试,检查信号状态。其中横坐标范围为 0 到 W,纵坐标范围为 0 到 H,总共测试 (W+1) * (H+1) 个点。
  给定信号塔的位置,请问这 (W+1)*(H+1) 个点中有多少个点被信号覆盖。
输入格式
  输入第一行包含四个整数 W, H, n, R,相邻整数之间使用一个空格分隔。
  接下来 n 行,每行包含两个整数 x, y,表示一个信号塔的坐标。信号塔可能重合,表示两个信号发射器装在了同一个位置。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
10 10 2 5
0 0
7 0
样例输出
57
评测用例规模与约定
  对于所有评测用例,1 <= W, H <= 100,1 <= n <= 100, 1 <= R <= 100, 0 <= x <= W, 0 <= y <= H。

1) .算法思路

  • 也是bfs暴搜题。

2).算法步骤

(1)信号塔问题的算法步骤如下:

1.读取输入的宽度(w)、高度(h)、信号塔数量(n)和信号范围(r)。
2.创建一个大小为(h+1)×(w+1)的布尔类型二维数组vis,用于记录每个位置是否被访问过。
3.初始化计数器count为0。
4.循环读取每个信号塔的坐标,并对每个信号塔执行以下步骤:
a. 调用bfs函数,传入当前信号塔的坐标。
5.输出计数器count的值。

(2)bfs函数的步骤如下:

1.创建一个双端队列deque。(单端队列也可以,但必须满足先进先出)。
2.将初始节点(信号塔的坐标)加入到deque的末尾。
3.当deque不为空时,执行以下步骤:
a. 从deque的开头取出一个节点poll。
b. 对于节点poll的四个相邻方向(上、下、左、右),执行以下步骤:
i. 计算相邻节点的坐标(dx, dy)。
ii. 如果相邻节点的坐标在合法范围内(0 <= dx <= w,0 <= dy <= h),且从当前节点到相邻节点的距离不超过信号范围r,并且相邻节点未被访问过,则执行以下操作:

  1. 将相邻节点标记为已访问。
  2. 将相邻节点加入到deque的末尾。
  3. 计数器count加1。
    循环结束后,返回结果。

3). 代码实例

package LanQiaoTest.BFS;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;

public class 信号塔 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static boolean[][] vis;
    static int w, h, n, r, count;
    static int[][] dis = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};


    //宽W,高H
    public static void main(String[] args) throws IOException {
        String[] s = br.readLine().split(" ");
        w = Integer.parseInt(s[0]);
        h = Integer.parseInt(s[1]);
        n = Integer.parseInt(s[2]);
        r = Integer.parseInt(s[3]);
        vis = new boolean[h + 1][w + 1];
        for (int i = 0; i < n; i++) {
            String[] temp = br.readLine().split(" ");
            bfs(new Node(Integer.parseInt(temp[0]), Integer.parseInt(temp[1])));
        }
        System.out.println(count);

    }

    private static void bfs(Node node) {
        Deque<Node> deque = new ArrayDeque<>();
        deque.addLast(node);
        while (!deque.isEmpty()) {
            Node poll = deque.pollFirst();
            for (int i = 0; i < 4; i++) {
                int dx = poll.x + dis[i][0];
                int dy = poll.y + dis[i][1];
                if (dx >= 0 && dx <= w && dy >= 0 && dy <= h && dis(node.x, node.y, dx, dy) <= r && !vis[dx][dy]) {
                    vis[dx][dy] = true;
                    deque.addLast(new Node(dx, dy));
                    count++;
                }
            }
        }
    }

    static double dis(int x1, int y1, int x2, int y2) {
        int dis = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
        return Math.sqrt(dis);
    }

    static class Node {
        int x;
        int y;

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




4).总结

八 . 清理水草


问题描述
  小蓝有一个 n * m 大小的矩形水域,小蓝将这个水域划分为 n 行 m 列,行数从 1 到 n 标号,列数从 1 到 m 标号。每行和每列的宽度都是单位 1 。
  现在,这个水域长满了水草,小蓝要清理水草。
  每次,小蓝可以清理一块矩形的区域,从第 r1 行(含)到第 r2 行(含)的第 c1 列(含)到 c2 列(含)。
  经过一段时间清理后,请问还有多少地方没有被清理过。
输入格式
  输入第一行包含两个整数 n, m,用一个空格分隔。
  第二行包含一个整数 t ,表示清理的次数。
  接下来 t 行,每行四个整数 r1, c1, r2, c2,相邻整数之间用一个空格分隔,表示一次清理。请注意输入的顺序。
输出格式
  输出一行包含一个整数,表示没有被清理过的面积。
样例输入
2 3
2
1 1 1 3
1 2 2 2
样例输出
2
样例输入
30 20
2
5 5 10 15
6 7 15 9
样例输出
519
评测用例规模与约定
对于所有评测用例,1 <= r1 <= r2 <= n <= 100, 1 <= c1 <= c2 <= m <= 100, 0 <= t <= 100。

1) .算法思路

  • 暴力枚举,当然有兴趣的小伙伴可以试试二维差分,时候复杂度会很快。

2).算法步骤

1.读取输入的n和m,表示地图的行数和列数。
2.创建一个大小为n x m的二维数组map,用于表示地图状态。
3.读取输入的t,表示清理操作的次数。
4.根据t的值,进行以下步骤t次:
(1)读取清理操作的起始坐标r1、c1和结束坐标r2、c2。
(2)针对起始坐标和结束坐标之间的矩形区域,在map数组中将对应的元素设置为1,表示清理过的区域。
5.初始化一个变量count,用于计算未清理的水草数量,初始值为0。
6.遍历map数组的每个元素:
(1) 如果元素的值为0,说明该位置上仍然有水草未清理,将count加1。
7.输出count的值,即为剩余未清理的水草数量。

3). 代码实例

package LanQiaoTest.枚举;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class 清理水草 {
    static int n, m, t;
    static int[][] map;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    public static void main(String[] args) throws IOException {
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        map = new int[n][m];

        t = Integer.parseInt(br.readLine());
        for (int i = 0; i < t; i++) {
            String[] temp = br.readLine().split(" ");
            int r1 = Integer.parseInt(temp[0]);
            int c1 = Integer.parseInt(temp[1]);
            int r2 = Integer.parseInt(temp[2]);
            int c2 = Integer.parseInt(temp[3]);
            for (int j = r1 - 1; j <= r2 - 1; j++) {
                Arrays.fill(map[j], c1 - 1, c2, 1);
            }
        }
        int count = 0;
        for (int[] ints : map) {
            for (int anInt : ints) {
                if (anInt == 0) {
                    count++;
                }
            }
        }
        System.out.println(count);

    }
}




4).总结

九 .最大滑行距离


问题描述
  小蓝准备在一个空旷的场地里面滑行,这个场地的高度不一,小蓝用一个 n 行 m 列的矩阵来表示场地,矩阵中的数值表示场地的高度。
  如果小蓝在某个位置,而他上、下、左、右中有一个位置的高度(严格)低于当前的高度,小蓝就可以滑过去,滑动距离为 1 。
  如果小蓝在某个位置,而他上、下、左、右中所有位置的高度都大于等于当前的高度,小蓝的滑行就结束了。
  小蓝不能滑出矩阵所表示的场地。
  小蓝可以任意选择一个位置开始滑行,请问小蓝最多能滑行多远距离。
输入格式
  输入第一行包含两个整数 n, m,用一个空格分隔。
  接下来 n 行,每行包含 m 个整数,相邻整数之间用一个空格分隔,依次表示每个位置的高度。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
4 5
1 4 6 3 1
11 8 7 3 1
9 4 5 2 1
1 3 2 2 1
样例输出
7
样例说明
  滑行的位置一次为 (2, 1), (2, 2), (2, 3), (3, 3), (3, 2), (4, 2), (4, 3)。 评测用例规模与约定
  对于 30% 评测用例,1 <= n <= 20,1 <= m <= 20,0 <= 高度 <= 100。
  对于所有评测用例,1 <= n <= 100,1 <= m <= 100,0 <= 高度 <= 10000。

1) .算法思路

  • bfs暴搜题。

2).算法步骤

1.导入所需的输入输出库。
2.定义两个数组 dx 和 dy,分别表示移动方向的横坐标和纵坐标的增量。
3.定义变量 max,用于记录当前路径的最大长度。
4.通过读取输入流,获取输入的行数和列数,并将其分别存储在变量 n 和 m 中。
5.创建一个大小为 (n+1) × (m+1) 的二维数组 G,用于存储矩阵数据。
6.使用循环遍历输入的每一行,并将每行的数据按空格分割后存储到数组 G 中。
7.初始化变量 ans 为 0,用于记录最终结果。
8.使用两层循环遍历矩阵 G 的每个元素,索引分别为 i 和 j:
(1) 将 max 初始化为 0,表示当前路径的最大长度。
(2) 调用深度优先搜索函数 dfs,传入矩阵的行数、列数、当前位置的横坐标和纵坐标、当前路径的步数和矩阵 G。
(3) 更新 ans,将 max 和 ans 中的较大值赋给 ans。
9.输出 ans,表示最长路径的长度。

3). 代码实例

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    static int[] dx = {0, 0, 1, -1};
    static int[] dy = {1, -1, 0, 0};
    static int max;
    //用不到标记数组

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String[] strings = in.readLine().split(" ");
        int n = Integer.parseInt(strings[0]);
        int m = Integer.parseInt(strings[1]);
        int[][] G = new int[n + 1][m + 1];
        //接收数据
        for (int i = 1; i <= n; i++) {
            strings = in.readLine().split(" ");
            for (int j = 1; j <= m; j++) {
                G[i][j] = Integer.parseInt(strings[j - 1]);
            }
        }
        //遍历矩阵
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                max = 0;
                dfs(n, m, i, j, 1, G);
                ans = Math.max(ans, max);
            }
        }
        System.out.println(ans);
    }

    private static void dfs(int n, int m, int x, int y, int step, int[][] G) {
        for (int i = 0; i < 4; i++) {
            int newx = x + dx[i];
            int newy = y + dy[i];
            if (newx >= 1 && newx <= n && newy >= 1 && newy <= m && G[newx][newy] < G[x][y]) {
                step++;
                max = Math.max(max, step);
                dfs(n, m, newx, newy, step, G);
                step--;
            }
        }
    }
}

4).总结

十 .序列最小值

问题描述
  小蓝有一个序列 a[1], a[2], ..., a[n]。
  给定一个正整数 k,请问对于每一个 1 到 n 之间的序号 i,a[i-k], a[i-k+1], ..., a[i+k] 这 2k+1 个数中的最小值是多少?当某个下标超过 1 到 n 的范围时,数不存在,求最小值时只取存在的那些值。
输入格式
  输入的第一行包含一整数 n。
  第二行包含 n 个整数,分别表示 a[1], a[2], ..., a[n]。
  第三行包含一个整数 k 。
输出格式
  输出一行,包含 n 个整数,分别表示对于每个序号求得的最小值。
样例输入
5
5 2 7 4 3
1
样例输出
2 2 2 3 3
评测用例规模与约定
  对于 30% 的评测用例,1 <= n <= 1000,1 <= a[i] <= 1000。
  对于 50% 的评测用例,1 <= n <= 10000,1 <= a[i] <= 10000。
  对于所有评测用例,1 <= n <= 1000000,1 <= a[i] <= 1000000。

1) .算法思路

  • 滑动窗口。

2).算法步骤

1.从输入中获取整数 n,表示数组的长度。
2.创建一个长度为 n 的整数数组 a,并从输入中获取 n 个整数,将其存储在数组 a 中。
3.从输入中获取整数 k。
4.创建三个长度为 n 的整数数组 q1、q2 和 res,分别用于存储中间结果。
5.初始化变量 hh 为 0,tt 为 -1。
6.使用循环遍历数组 a 的每个元素,索引为 i:
(1)如果队列 q1 非空且队列头部元素的下标小于等于 i – k,则将头部元素出队。
(2)在队列 q1 非空且队列尾部元素对应的数组 a 的值大于等于 a[i] 时,将尾部元素出队。
(3)将当前元素的下标 i 入队到队列 q1 的尾部。
(4)将 res[i] 的值设为队列 q1 的头部元素对应的数组 a 的值。
7.初始化变量 hh 为 0,tt 为 -1。
8.使用循环从 n-1 开始到 0,递减遍历数组 a 的每个元素,索引为 i:
(1)如果队列 q2 非空且队列头部元素的下标大于等于 i + k,则将头部元素出队。
(2)在队列 q2 非空且队列尾部元素对应的数组 a 的值大于等于 a[i] 时,将尾部元素出队。
(3)将当前元素的下标 i 入队到队列 q2 的尾部。
(4)将 res[i] 的值设为 res[i] 和队列 q2 的头部元素对应的数组 a 的值中的较小值。
9.使用循环遍历数组 res 的每个元素,索引为 i,输出 res[i] 的值,以空格分隔。

3). 代码实例

import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        for(int i = 0; i < n; i++) a[i] = scanner.nextInt();
        int k = scanner.nextInt();
        int[] q1 = new int[n];
        int[] q2 = new int[n];
        int[] res = new int[n];
        int hh = 0, tt = -1;
        for(int i = 0; i < n; i++){
            if(hh <= tt && q1[hh] < i - k) hh++;
            while(hh <= tt && a[q1[tt]] >= a[i]) tt--;
            q1[++tt] = i;
            res[i] = a[q1[hh]];
        }
        hh = 0;
        tt = -1;
        for(int i = n - 1; i >= 0; i--){
            if(hh <= tt && q2[hh] > i + k) hh++;
            while(hh <= tt && a[q2[tt]] >= a[i]) tt--;
            q2[++tt] = i;
            res[i] = Math.min(res[i], a[q2[hh]]);
        }
        for(int i = 0; i < n; i++){
            System.out.print(res[i] + " ");
        }
    }
}

4).总结

十一 .数位和最小


问题描述
  一个数的数位和是指这个数各个数位上的数字之和。例如 2023 的数位和是 2+0+2+3=7 。
  对于以下这些数(8行,每行8个,共64个),请问数位和最小的数是多少?(如果有多个,请回答出现最早的那个)
  454771 329157 801601 580793 755604 931703 529875 361797
  604358 529564 574776 821517 195563 688516 223321 607845
  284772 603562 543328 707484 533688 380468 233733 257995
  896582 670074 912386 702393 722092 834842 126346 606526
  376981 910643 413754 945725 817853 651778 350775 676550
  316935 487808 939526 900568 423326 298936 927671 539773
  136326 717022 886675 466684 436470 558644 267231 902422
  743580 857864 529622 320921 595409 486860 951114 558787

1) .算法思路

  • 暴力!!

2).算法步骤

1.创建一个 8×8 的整数二维数组 G,用于存储输入的数据。
2.通过输入流读取用户输入的数据,并将其填充到数组 G 中。
3.初始化变量 answer 和 min,分别用于存储最小的和对应的整数。
4.遍历数组 G 的每个元素:
(1)将当前元素保存在变量 a 中。
(2)初始化变量 sum 为 0,用于计算当前整数的每位数字之和。
(3)使用循环将 a 中的每个位上的数字相加,将结果累加到 sum 中。
(4)如果 sum 小于 min,则更新 min 和 answer 的值为当前整数。
5.输出 answer,即具有最小数字之和的整数。

3). 代码实例

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int[][] G = new int[8][8];
        String[] s;
        //接受数据
        int answer = 0;
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < 8; i++) {
            s = in.readLine().split(" ");
            for (int j = 0; j < 8; j++) {
                G[i][j] = Integer.parseInt(s[j]);
                int a = G[i][j];
                int sum = 0;
                while (a > 0) {
                    sum += a % 10;
                    a /= 10;
                }
                if (sum < min) {
                    min = sum;
                    answer = G[i][j];
                }
            }
        }
        System.out.println(answer);
    }
}

4).总结

  • 答案:223321

十二 .对折绳子

问题描述
  小蓝有一根长度为 L 的绳子,每对折一次,长度变为原来的一半,请问对折多少次后长度不超过 1 。
  例如,当 L=6 时,对折一次长度为 3,对折两次长度为 1.5 ,对折 3 次长度为 0.75,所以 3 次后长度不超过 1 。
输入格式
  输入一行包含一个整数 L 。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
6
样例输出
3
样例输入
255
样例输出
8
样例输入
256
样例输出
8
样例输入
257
样例输出
9
评测用例规模与约定
  对于 50% 评测用例,1 < L <= 10**9 (10的9次方)。
  对于所有评测用例,1 < L <= 10**18 (10的18次方)。

1) .算法思路

  • 注意数据范围,1e19。

2).算法步骤

1.创建一个Scanner对象,用于从控制台接收输入。
2.从控制台输入一个数L。
3.初始化一个变量ans为0,用于记录除以2的操作次数。
4.进入一个无限循环:
(1) 将L除以2。
(2) 将ans加1。
(3) 检查L是否小于1,如果是,跳出循环。
5.输出ans的值,即为除以2的操作次数。

3). 代码实例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Double L = scanner.nextDouble();
        long ans = 0;
        while (true) {
            L /= 2;
            ans++;
            if (L <= 1 )break;
        }
        System.out.println(ans);
    }
}

4).总结

十三 .删除字符

问题描述
  给定一个由大写字母组成的长度为 n 的字符串,请在字符串中删除 m 个字符,使得剩下的字符串的字典序最小。
输入格式
  输入的第一行包含两个整数 n, m ,用一个空格分隔。
  第二行包含一个长度为 n 的字符串。
输出格式
  输出一行包含一个长为 n-m 的字符串,表示答案。
样例输入
7 3
LANQIAO
样例输出
AIAO
评测用例规模与约定
  对于 30% 的评测用例,1 <= m < n <= 30。
  对于 60% 的评测用例,1 <= m < n <= 1000。

1) .算法思路

  • 模拟枚举。(也可以用双向队列实现栈的方向去用。)

2).算法步骤

1.从标准输入中读取两个整数n和m,分别表示字符串的长度和最大删除字符数。
2.从标准输入中读取一个字符串str。
3.创建一个StringBuilder对象result,用于存储最终的结果字符串。
4.创建一个整数变量deleteCount,用于记录已删除的字符数,初始化为0。
5.遍历字符串str的每个字符:
a. 获取当前字符c。
b. 在删除字符数未达到最大删除字符数m、结果字符串result非空且结果字符串result的最后一个字符大于当前字符c的条件下,执行以下循环:
(1)删除结果字符串result的最后一个字符。
(2)增加已删除字符数deleteCount。
c. 将当前字符c添加到结果字符串result中。
6.如果删除字符数deleteCount小于最大删除字符数m,执行以下操作:
(1)从结果字符串result的末尾删除长度为m – deleteCount的子字符串。
7.将结果字符串result输出到标准输出。

3). 代码实例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        String str = scanner.next();

        StringBuilder result = new StringBuilder();
        int deleteCount = 0;

        for (int i = 0; i < n; i++) {
            char c = str.charAt(i);

            while (deleteCount < m && result.length() > 0 && result.charAt(result.length() - 1) > c) {
                result.deleteCharAt(result.length() - 1);
                deleteCount++;
            }

            result.append(c);
        }

        if (deleteCount < m) {
            result.delete(result.length() - (m - deleteCount), result.length());
        }

        System.out.println(result.toString());
    }
}

4).总结

  • 字符串字典序的比较。
  • 字典序:长度不能直接决定大小,字符串的大小是由左边开始最前面的字符决定的。

以上只是我个人的思路及代码,可能存在错误,大家如果有发现错误的,可以在下面评论区中指出,感谢观看~💪💪💪。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年12月15日
下一篇 2023年12月15日

相关推荐