第十一届蓝桥杯Java B组题解

  • Post author:
  • Post category:java




A.门牌制作

在这里插入图片描述



题解

624
#include<iostream>
using namespace std;
int nums[10];
void solve(int i)
{
    while(i)
    {
        nums[i%10]++;
        i /= 10;
    }
}
int main()
{
    for(int i = 1; i <= 2020; i++)
        solve(i);
    cout << nums[2];
    return 0;
}



B.寻找2020

在这里插入图片描述


📎2020.txt



题目分析

将文本的每一行每一列以及斜线存到数组里,对数组进行遍历,出现一个2020答案加一即可。

16520
import java.io.*;
import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/1/29 13:31
 */
public class B {
    static final int N = 300;
    static char[][] ch = new char[N][N];
    static String[] strl = new String[N];
    static String[] strc = new String[N];
    static String str;
    static int ans;

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader("src/lanqiao/y2020_11/2020.txt"));

        for (int i = 0; i < 300; i++) {
            String s = in.readLine();
            ch[i] = s.toCharArray();
            strl[i] = s;
        }
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (strl[i].startsWith("2020", j)) ans++;
            }
        }
        for (int i = 0; i < N; i++) {
            StringBuilder s = new StringBuilder();
            for (int j = 0; j < N; j++) {
                s.append(ch[j][i]);
            }
            String tmp = s.toString();
            strc[i] = tmp;
        }
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (strc[i].startsWith("2020", j)) ans++;
            }
        }
        for (int i = 0; i < 300; i++) {
            for (int j = 0; j < 300; j++) {
                //检查最后一个坐标是否符合
                if (i + 4 <= 300 && j + 4 <= 300) {
                    String s = "";
                    s += ch[i][j];
                    s += ch[i + 1][j + 1];
                    s += ch[i + 2][j + 2];
                    s += ch[i + 3][j + 3];
                    if (s.equals("2020")) {
                        ans++;
                    }
                }
            }
        }
        System.out.println(ans);
    }
}



C.蛇形填数

在这里插入图片描述



题目分析

为了便于计算可以将该矩阵顺时针旋转45度,如下图所示:

在这里插入图片描述

则第20行20列旋转后为第20 * 2 – 1行第20个,即第39行第20个,前38行有

(38 + 1) * 38 / 2 = 741

加上第39行的20,一共是761。



题解

761



D.七段码

在这里插入图片描述



题目分析

可以将a b c d e f g七个灯管抽象为七个顶点,用edge数组表示灯管是否相连,

edge[i][j] = 1

,表示第i个顶点与第j个顶点相连,即灯管相连。

深搜每一个状态,用并查集判断某一个顶点是否与其他顶点在一个图里,在不影响图的连通性的基础上,将这个顶点加入这个图里。原理为若所有顶点的父亲顶点都一样,则在一个集合里,否则需要合并。实现并查集需要实现它的三个方法,分别为

init()

,

find()

,

join()



init()

public static void init() {
       for (int i = 1; i <= 7; i++) {
           fa[i] = i;//初始化父亲顶点
       }
}



find()

public static int find(int r) {
    if (r == fa[r]) return r;
    else return find(fa[r]);
}

普通的find方法,在查询过程中可能会栈溢出,下面给出路径压缩算法

public static int find(int r) {
    if (r == fa[r]) return r;
    else {
        fa[r] = find(fa[r]);
        return fa[r];
    }
}



join()

public static void join(int x, int y) {
    int xfa = find(x);
    int yfa = find(y);
    if (xfa != yfa) {
        fa[xfa] = yfa;//合并哪个都行
    }
}



题解

80
public class D {
    static final int N = 10;
    static int[] fa = new int[N];
    static int[][] edge = new int[N][N];
    static boolean[] vis = new boolean[N];
    static int ans;

    public static void main(String[] args) {
        link();
        dfs(1);
        System.out.println(ans);
    }

    public static void link() {
        /*
        a b c d e f g
        1 2 3 4 5 6 7
         */
        //将连通的情况置为1
        edge[1][2] = edge[1][6] = 1;
        edge[2][1] = edge[2][3] = edge[2][7] = 1;
        edge[3][2] = edge[3][4] = edge[3][7] = 1;
        edge[4][3] = edge[4][5] = 1;
        edge[5][4] = edge[5][6] = edge[5][7] = 1;
        edge[6][1] = edge[6][5] = edge[6][7] = 1;
        edge[7][2] = edge[7][3] = edge[7][5] = edge[7][6] = 1;
    }

    public static void dfs(int d) {
        //d表示第几个灯管,范围为1~7
        if (d > 7) {
            init();
            for (int i = 1; i <= 7; i++) {
                for (int j = 1; j <= 7; j++) {
                    if (edge[i][j] == 1 && vis[i] && vis[j]) {
                        //如果i,j连通,并且i,j灯管亮了,合并i,j
                        join(i, j);
                    }
                }
            }
            int k = 0;
            for (int i = 1; i <= 7; i++) {
                //如果灯管亮了并且自身是父亲结点
                if (vis[i] && fa[i] == i) k++;
            }
            //如果所有顶点在一个集合里
            if (k == 1) ans++;
            return;
        }
        vis[d] = true;//将第d个灯管点亮
        dfs(d + 1);//在第d个灯管点亮的情况下处理第d + 1个灯管
        vis[d] = false;//将第d个灯管关闭
        dfs(d + 1);//在第d个灯管关闭的情况下处理第d + 1个灯管

    }

    public static void init() {
        for (int i = 1; i <= 7; i++) {
            fa[i] = i;//初始化父亲顶点
        }
    }

    public static int find(int r) {
        if (r == fa[r]) return r;
        else {
            fa[r] = find(fa[r]);
            return fa[r];
        }
    }

    public static void join(int x, int y) {
        int xfa = find(x);
        int yfa = find(y);
        if (xfa != yfa) {
            fa[xfa] = yfa;
        }
    }
}



E.排序

在这里插入图片描述



题目分析

题目要求字符串长度最短,在长度最短的情况下使得字典序最小,逆序的字符串需要比较的次数最多,为

(n - 1) * n / 2

,取最接近100并且使结果大于100的n,得 n = 15,此时比较次数为105,要使次数减少5可以让第六个字母放在字符串的首位,结果是

jonmlkihgfedcba。

简单验证一下:

在这里插入图片描述

答案正确!



F.成绩分析

在这里插入图片描述

在这里插入图片描述



题目分析

遍历一遍即可

import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/1/28 19:28
 */
public class F {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        int sum = 0;
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
            sum += a[i];
        }
        int max = a[0], min = a[0];
        for (int i = 0; i < n; i++) {
            max = Math.max(max, a[i]);
            min = Math.min(min, a[i]);
        }
        System.out.println(max);
        System.out.println(min);
        System.out.printf("%.2f", sum * 1.0 / n);
    }
}



G.单词分析

在这里插入图片描述

在这里插入图片描述



题目分析

可以用map将字母与出现次数映射在一起,遍历一遍字符串,得到每一个字母出现的次数,比较得出最大值即可。



题解

import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/1/28 20:36
 */
public class G {
        public static void main(String[] args) {
                Scanner scanner = new Scanner(System.in);
                HashMap<Character, Integer> ci = new HashMap<>();
                String s = null;
                char ans = '\0';
                s = scanner.next();
                int max = -1;
                int len = s.length();
                for (int i = 0; i < len; i++) {
                        char ch = s.charAt(i);
                        Integer value = ci.get(ch);
                        if (value == null) {
                                ci.put(ch,1);
                        } else {
                                value++;
                                ci.put(ch,value);
                        }
                }
                Set<Character> chs = ci.keySet();
                for(Character ch : chs) {
                        if (max < ci.get(ch)) {
                                max = ci.get(ch);
                                ans = ch;
                        }
                }
                System.out.println(ans);
                System.out.println(ci.get(ans));
        }
}

这道题用C++写更方便

#include <iostream>
#include <cstring>
using namespace std;
char ch[1005];
int nums[1005];
int main()
{
    int ansch = 0, ansnum = 0;
    cin >> ch;
    int len = strlen(ch);
    for(int i = 0; i < len; i++)
        nums[ch[i]]++;
    for(int i = 'a'; i <= 'z'; i++)
    {
        if(ansnum < nums[i])
        {
            ansnum = nums[i];
            ansch = i;
        }
    }
    cout << (char)ansch << endl << ansnum;
    return 0;
}



H.数字三角形

在这里插入图片描述

在这里插入图片描述



题目分析

求最大的和可以用到动态规划,最后和比较大的数都会集中在最后一行。但是本道题目限制了向左走和向右走得步数差不超过一,也就是说答案集中在最后一行得中间位置,如果三角形有奇数层,则中间位置即为解,否则中间两个位置得最大值为解。



题解

import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/1/29 18:42
 */
public class H {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int lev = scanner.nextInt();
        int[][] dp = new int[lev + 1][lev + 1];
        for (int i = 1; i <= lev; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i][j] = scanner.nextInt();
            }
        }
        for (int i = 1; i <= lev; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i][j] += Math.max(dp[i - 1][j - 1], dp[i - 1][j]);
            }
        }
        if (lev % 2 == 0) {
            System.out.println(Math.max(dp[lev][lev / 2], dp[lev][lev / 2 + 1]));
        } else System.out.println(dp[lev][lev / 2 + 1]);
    }

}



I.子串分值和

在这里插入图片描述

在这里插入图片描述



题目分析

从题目中可以看出评测用例的规模为105,因此暴力枚举两层循环会超时,只能独辟蹊径解决问题。

首先将测试用例分成所有的子串,再把每个子串中不重复的字母表示出来。

a         a
ab        a b
aba       a b
abab      a b
ababc     a b     c
 b          b
 ba         b a
 bab        b a
 babc       b a   c
  a           a
  ab          a b
  abc         a b c
   b            b
   bc           b c
    c             c

一开始所有的字符都未出现过,将他们的位置都初始化-1,一旦出现过,更新其位置。

类似“左边两条路右边三条路一共有6种走法”,对于此刻枚举的第i的字符来说,从其前一次出现的位置+1到此刻i都是其可能开始的地方(从上面的数据可以体会到,例如a一开始未出现过,位置为-1,下一个位置为0,i= 0,所以a开始于0,a开始的地方有1个;例如b,上次出现的位置为-1,则从0到1都是其开始的地方,所以在算以a为首字母的子串中有b,以b开头的字串也有b,b开始的地方有两个);而从此刻i到结尾则可能是其结束的地方。比如,ababc对应下标01234,对于第二个a来说,下标[x,y]x的取值范围是[1,2],Y则是[1,4]。这样一来的话左边可选有2,右边可选有4,相乘为8;对每一个字符都用这样的思路去思考,最终就是O(n)复杂度的解。



题解

import java.util.Arrays;
import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/1/30 17:47
 */
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        char[] chs = str.toCharArray();
        int len = chs.length;
        int[] loc = new int[26];
        long ans = 0;
        Arrays.fill(loc, -1);
        for (int i = 0, _len = len; i < len; i++, _len --) {
            ans += (long) (i - loc[chs[i] - 'a']) * _len;
            //i - loc[chs[i] - 'a']表示开始的位置有几个,_len表示结束的位置有几个
            loc[chs[i] - 'a'] = i;//更新位置
        }
        System.out.println(ans);
    }
}



J.装饰珠

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



版权声明:本文为weixin_51624761原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。