蓝桥杯备赛笔记-----题目和相关算法知识

前言:

作为一个只参加过校内ACM选拔还没进的人来说,参加这个蓝桥杯对我是一个不小的挑战(但我这个人就是喜欢挑战自己)。写博客的目的是单纯的记录一下自己的备赛历程,也是锻炼一下我对外输出的能力。文章如果能帮助到你,那自然是再好不过了。本人水平有限,若文章出现错误,还请见谅,若能指出错误那自然是十分感谢。


字符类题目

小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组 成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。

  • 输入描述

    输入一行包含一个单词,单词只由小写英文字母组成。

    对于所有的评测用例,输入的单词长度不超过 1000。

  • 输出描述

    输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪 个。如果有多个字母出现的次数相等,输出字典序最小的那个。

    第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。

  • 输入输出样例

    示例 1

        输入:

lanqiao

         输出:

a                                                                                                                                                2
  • 运行限制

    • 最大运行时间:1s
    • 最大运行内存: 256M

这道题在官网的备注是简单,我的思路不需要用到什么算法,直接暴力解题。既然是有字符和次数的对应关系,我的第一想法就是用一个HashMap来存储数据,因为HashMap正好是键值对的二元关系。但是由于我好久没有动我的脑壳咯,加上没有什么做题经验,这第一道题花了我2个小时修修改改,才过的。

 话不多说,上代码!

import java.util.*;

/**
 * @autor asdas
 * @creat 2022-12-20-10:57
 */
public class test {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        String s=scan.next();
        HashMap<Character, Integer> hashMap=new HashMap();//存入的键是字符,值是字符出现的次数
        char[] a=s.toCharArray();//获取输入的字符串的字符数组,用于后面遍历
        for(char t:a){
            int cout=0;//计数器,遇到此次循环相同的字符就自增
            for(int i=0;i<a.length;i++){
                if(t==a[i]){
                    cout++;
                }
            }
            hashMap.put(t,cout);//这里还利用了一下HashMap存入相同的键会覆盖原有数据的特点,不断更新这个字符的值
        }
        Set<Map.Entry<Character,Integer>> entrySet=hashMap.entrySet();//获取映射所有键值对关系的Set集合,用于后面遍历
        char maxChar=' ';//用于保存遍历的时候的最大出现次数的字符
        int  maxcout=0;//保存最大出现次数
        for(Map.Entry<Character,Integer>ent:entrySet){//最常见的遍历HashMap的方法
            char tempChar=ent.getKey();
            int tempcout=ent.getValue();
            if(tempcout>maxcout){//如果本次循环的次数大于最大次数,就更新
                maxChar=tempChar;
                maxcout=tempcout;
            }
        }
        System.out.println(maxChar);
        System.out.println(maxcout);


        scan.close();
    }
}

ps:这个题解并不是满分的,因为我没有限制最大个数相同的字符按照字典顺序大小输出。但是蓝桥杯官网上的样例是都通过了的

算数类题目

成绩统计--12月24日

题目描述:

小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。

如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。

请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整 数。

输入描述

输入的第一行包含一个整数 n (1≤n≤104)n (1≤n≤104),表示考试人数。

接下来 nn 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。

输出描述

输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分 四舍五入保留整数。

输入输出样例

示例

输入:

7,80,92,56,74,88,100,0

输出:

71%

43%

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

分析:这道题方法有很多,我这里用了一个大数类(我喜欢这么叫)BigDecimal,首先来解释一下这个类是什么。

        BigDecimal类,通常用于商业用途的计算,比如你余额宝里头的小数点计算。它存在于java.math包底下,是Java提供的对超过16位的数进行精准运算的APl类。类似于包装流一样的存在,这个可以看作是对基本数字的包装。不能够通过+,-,*,/来对该类的对象进行算数运算,它有着自己提供的方法,通过调用BigDecimal类中的方法来对该类进行运算,参与运算的数都要为大数类对象,例如除法运算调用如下的方法,第一个参数为被除数,需要是大数类对象,第二个参数为舍入的位数,第三个参数为舍入模式(向上舍入还是向下舍入等等)

divide(BigDecimal divisor, int scale, int roundingMode)
          返回一个 BigDecimal,其值为 (this / divisor),其标度为指定标度。

                                                                                                           --java 1.6.0版本 API中文帮助文档

知道了这个大数类,应该也能明白我为啥要用大数类。一开始看到处理数据和小数点,脑子里就想起来大数类,因为对它有个印象就是它可以控制保留的结果的位数。我拿除法举例子也是有目的的,因为我接下来就用到了这个方法。

 代码呈上

import java.math.BigDecimal;
import java.util.Scanner;

/**
 * @autor asdas
 * @creat 2022-12-30-11:18
 */
public class 平均数 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        double num = scan.nextFloat();
        double c = 0;
        double a = 0;
        for (int i = 0; i < num; i++) {
            int temp = scan.nextInt();
            if (temp >= 60 && temp<85) {
                c++;
            } else if (temp >= 85) {
                c++;
                a++;
            }
        }

        BigDecimal bigDecimal=new BigDecimal(c);//包装数据
        BigDecimal bigDecimal1=new BigDecimal(a);//包装数据
        BigDecimal bigDecimal2=new BigDecimal(num);//包装数据
        //除法调用
        BigDecimal result1=bigDecimal.divide(bigDecimal2,2,BigDecimal.ROUND_HALF_UP);
        //乘法调用
        result1=result1.multiply(new BigDecimal(100));
        BigDecimal resutlt2= bigDecimal1.divide(bigDecimal2,2,BigDecimal.ROUND_HALF_UP);
        resutlt2=resutlt2.multiply(new BigDecimal(100));
        System.out.println( result1.intValue()+"%");//输出结果
        System.out.println(resutlt2.intValue()+ "%");//输出结果
        scan.close();
    }
}

Ps:不建议double类型的数据直接放进BigDecimal类中,因为实际上BigDecimal类的double类构造方法的结果具有一定的不可预知性,结果有可能失真。所以一定要使用double的构造函数的话,建议将double转换成String之后调用BigDecimal类的字符串构造函数,比如调用Double.valueOf()方法将double转换成String,结果就不会有失真的可能。我这里不用是因为我后面再次学习才知道这个,懒得改了。


动态规划类题目

数字三角形--12月26日

来源:蓝桥杯备赛专区

题目位置:

用户登录

题目描述

上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。

路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。

输入描述

输入的第一行包含一个整数 N (1≤N≤100)N (1≤N≤100),表示三角形的行数。

下面的 NN 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。

输出描述

输出一个整数,表示答案。

输入输出样例

示例

输入

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出

27

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

分析:一开始看到这个题,就想着能不能就局部选取最优解来完成结果的寻找呢,我只要动态扫描每个数底下谁最小就从哪里走不就好了,后面发现一个问题,那就是这并不能确定现在的最优解在接下来也会是最优的,于是乎我想着能不能再用一个啥玩意来记录一下,但是没有思路。看到题目标签上有个动态规划,我就去搜了一下这是啥,结果发现这个动态规划和我前面的思路一模一样,我就按照动态规划的模版来解决这个问题了。

按照惯例,介绍一下动态规划是个啥东西。

(以下的内容参考了Hollis Chuang转载的文章:告别动态规划,连刷40道动规算法题,我总结了动规的套路

文章链接告别动态规划,连刷40道动规算法题,我总结了动规的套路_Hollis Chuang的博客-CSDN博客

  • 动态规划,说白了就是一个不断拆分问题,将大问题拆分成小问题的一种方法。它的核心,就是利用一个历史记录来保存我们计算过的数据,并通过这个历史记录来解决选择最优解的问题。一般来说这个历史记录通过一维数组或者是二维数组来保存。
  • 用这道题来解释就是:假设a[][]数组保存这个三角形阶梯。由于我们需要求出最大的和,所以我们保存的历史记录,也就应该是每一次选择之后两数相加,我们用一个二维数组dp[][] 来保存我们每次向下走的时候选取的最大数字和上一层相加产生的结果,并将这个结果放在dp[][]中对应的位置。因此,此时dp数组的意义就是保存每一次选择相加后的最大数。
  • 在确定了dp数组的意义之后,我们需要做的事情,就是如何求出dp数组中的每一个数。这个过程是根据题目的要求来具体确定的,也就是说,dp数组中的关系式,是需要根据题目来动态确定的,在这道题中,因为是选择该数的下一层左边或者右边的数,且要选择最大的数相加,所以为了方便确定关系式,我们不妨从dp数组最后一层,也就是最终路径相加后的结果开始看起,由于最后一层的数是由左上角或右上角的数加上a[][]数组中与最后一层对应位置的数得到的,所以我们可以确定一个关系式

dp[i][j]=Max(dp[i-1][j-1] , dp[i-1][j])+a[i][j]

  •  这个关系式显然是一个动态更新的过程,这也是动态规划名字的由来。

那么现在有了关系式之后,接下来要做的就是边界情况的确定了,这些就在代码中体现了

import java.util.Scanner;

/**
 * @autor asdas
 * @creat 2022-12-22-11:25
 */
public class Num {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
//        int n=0;//行数
//        n=scan.nextInt();
//        int[][] a=new int[n+1][n+1];
//        int[][] dp=new int[n+1][n+1];//dp是历史记录数组
//        for(int i=0;i<n;i++){
//            for(int j=0;j<=i;j++){
//                a[i][j]=scan.nextInt();
//            }
//        }
//        dp[0][0]=a[0][0];//初始化第一个数
//        for(int i=1;i<n;i++){
//            for(int j=0;j<=i;j++){
//                if(j==0){
//                    dp[i][j]=dp[i-1][j]+a[i][j];
//                }else if(j==i){
//                    dp[i][j]=dp[i-1][j-1]+a[i][j];
//                }else {
//                    dp[i][j] = Math.max(dp[i - 1][j - 1], dp[i - 1][j]) + a[i][j];
//                }
//
//            }
//        }
//        int max=dp[1][1];
//        for(int i=0;i<=n;i++){
//            for(int j=0;j<=i;j++){
//               if(dp[i][j]>max){
//                   max=dp[i][j];
//               }
//            }
//        }
//        if(n%2==0)
//          System.out.println(Math.max(dp[n][n/2],dp[n][(n/2)+1]));
//        else
//          System.out.println(dp[n][(n/2)+1]);
//        System.out.println(max);
//        scan.close();
        int n=scan.nextInt();
        int [][]a=new int[n+1][n+1];
        int [][]c=new int[n+1][n+1];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                a[i][j]=scan.nextInt();
            }
        }
        c[1][1]=a[1][1];
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i;j++){
                c[i][j]=a[i][j]+Math.max(c[i-1][j],c[i-1][j-1]);
            }
        }
        if(n%2==0)
            System.out.println(Math.max(c[n][n/2],c[n][(n/2)+1]));
        else
            System.out.println(c[n][(n/2)+1]);
        scan.close();

    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有着一半自律的海鸥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值