第十四届蓝桥杯大赛——真题训练第11天
目录
第一题:蓝肽子序列_求最长公共子序列
题目描述
L 星球上的生物由蛋蓝质组成,每一种蛋蓝质由一类称为蓝肽的物资首尾连接成一条长链后折叠而成。
生物学家小乔正在研究 L 星球上的蛋蓝质。她拿到两个蛋蓝质的蓝肽序列,想通过这两条蓝肽序列的共同特点来分析两种蛋蓝质的相似性。
具体的,一个蓝肽可以使用 1 至 5 个英文字母表示,其中第一个字母大写,后面的字母小写。一个蛋蓝质的蓝肽序列可以用蓝肽的表示顺序拼接而成。
在一条蓝肽序列中,如果选取其中的一些位置,把这些位置的蓝肽取出,并按照它们在原序列中的位置摆放,则称为这条蓝肽的一个子序列。蓝肽的子序列不一定在原序列中是连续的,中间可能间隔着一些未被取出的蓝肽。
如果第一条蓝肽序列可以取出一个子序列与第二条蓝肽序列中取出的某个子序列相等,则称为一个公共蓝肽子序列。
给定两条蓝肽序列,找出他们最长的那个公共蓝肽子序列的长度。
输入描述
输入两行,每行包含一个字符串,表示一个蓝肽序列。字符串中间没有空格等分隔字符。
其中有 ,两个字符串的长度均不超过 10001000。
输出描述
输出一个整数,表示最长的那个公共蓝肽子序列的长度。
输入输出样例
示例
输入
LanQiaoBei LanTaiXiaoQiao
输出
2
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
题目分析
(1)字符串切割(存储每个以大写字母为开头的单词)
(2)最长公共子序列问题(LCS)
- 最长公共子序列我们需要分别遍历字符串S1和字符串S2
- 遍历比较的时候只会出现两种情况:字符串相等或字符串不等
- 对应这两种状态分别给出两种dp状态转移方程:
相等:dp[i][j]=dp[i-1][j-1]+1
不相等:dp[i][j]=max(dp[i-1][j],dp[i][j-1])dp[i][j]的表示含义:字符串S1的前i个字符和字符串S2的前j个字符可以构成最长公共子序列为:dp[i][j]
参考原文链接:https://blog.csdn.net/m0_55858611/article/details/129783258
题目代码
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class 蓝肽子序列 { public static void main(String[] args) { Scanner sca = new Scanner(System.in); String s1 = sca.next(); String s2 = sca.next(); char[] chars1 = s1.toCharArray(); char[] chars2 = s2.toCharArray(); ArrayList<String> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); int temp = 0; //切割字符串 for (int i = 1; i < chars1.length; i++) { if (chars1[i] >= 'A' && chars1[i] <= 'Z') { list1.add(s1.substring(temp, i)); temp = i; //当最后一个单词为大写时 if (i == chars1.length - 1) { list1.add(chars1[i] + ""); } //当最后一个单词为小写时 } else if (i == chars1.length - 1) { list1.add(s1.substring(temp, s1.length())); } } temp = 0; //切割字符串 for (int i = 1; i < chars2.length; i++) { if (chars2[i] >= 'A' && chars2[i] <= 'Z') { list2.add(s2.substring(temp, i)); temp = i; if (i == chars2.length - 1) { list2.add(chars2[i] + ""); } } else if (i == chars2.length - 1) { list2.add(s2.substring(temp, s2.length())); } } //最长公共子序列 int[][] dp = new int[list1.size() + 1][list2.size() + 1]; for (int i = 1; i <= list1.size(); i++) { for (int j = 1; j <= list2.size(); j++) { if (list1.get(i - 1).equals(list2.get(j - 1))) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); } } } System.out.println(dp[list1.size()][list2.size()]); } }
第二题: 时间显示
题目描述
小蓝要和朋友合作开发一个时间显示的网站。
在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 年 11 月 11 日 00:00:00 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
输入描述
输入一行包含一个整数,表示时间。
输出描述
输出时分秒表示的当前时间,格式形如
HH:MM:SS
,其中HH
表示时,值为 0 到 23,MM
表示分,值为 0 到 59,S
表示秒,值为 0 到 59。时、分、秒 不足两位时补前导 0。输入输出样例
示例 1
输入
46800999
输出
13:00:00
示例 2
输入
1618708103123
输出
01:08:23
评测用例规模与约定
对于所有评测用例,给定的时间为不超过 10181018 的正整数。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
题目分析
该题有两种方法可解:
1. 使用Java自带的API进行计算
* 思路: 将输入的毫秒数创建为Date日期对象,使用SimpleDateFormat设置为"HH:mm:ss"的格式
如果想输出其他格式,我们可以任意转换,比如:
SimpleDateFormat ft = new SimpleDateFormat ("HH-mm-ss");
Date date = new Date(mills) mils只能是毫秒数 计算从
1970-01-01 08:00:00开始经过了mils毫秒后的时间为多少
- * 难点: Date类 SompleDateFormat类的使用
2. 通过计算毫秒数,将范围确定为一天内,并按照题意忽略毫秒位,计算出其所代表的时间。1秒等于1000毫秒
题目代码
方法一:
import java.sql.Date; import java.text.SimpleDateFormat; import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改 public class Main { public static void main(String[] args) { /* * 思路: 将输入的毫秒数创建为Date日期对象,使用SimpleDateFormat设置为"HH:mm:ss"的格式 * 难点: Date类 SompleDateFormat类的使用 */ Scanner sc = new Scanner(System.in); long mills = sc.nextLong(); //这里剪去8个小时的时间是因为这里的Date是以1970-01-01 08:00:00开始的 //比题目中要求的时间早8个小时,所以要剪去。 mills -= 8 * 60 * 60 * 1000; Date date = new Date(mills); SimpleDateFormat ft = new SimpleDateFormat("HH:mm:ss"); System.out.println(ft.format(date)); } }
方法二:
import java.util.Scanner; public class 时间显示 { public static void main(String[] args) { Scanner sca = new Scanner(System.in); long n = sca.nextLong(); //当天剩余的秒数 1s==1000ms long miao = n / 1000 % (24 * 60 * 60); long HH = miao / 3600; //当时那一小时的分钟为 long MM = miao % 3600/60; long SS = miao % 3600%60; StringBuilder sBuilder = new StringBuilder(); if (HH < 10) { sBuilder.append("0" + HH + ":"); } else { sBuilder.append("" + HH + ":"); } if (MM < 10) { sBuilder.append("0" + MM + ":"); } else { sBuilder.append("" + MM + ":"); } if (SS < 10) { sBuilder.append("0" + SS); } else { sBuilder.append("" + SS); } // String str = sBuilder.toString(); System.out.println(sBuilder); } }
第三题:顺子日期
问题描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。
例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。
小明想知道在整个 2022 年份中,一共有多少个顺子日期?
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
题目分析
1)使用Calendar日期类
2)将日期转为字符串进行判断是否为顺子日期
题目代码
import java.util.Calendar; public class 顺子日期 { public static void main(String[] args) { Calendar cal = Calendar.getInstance(); cal.set(2022, 0, 1); Calendar cal2 = Calendar.getInstance(); cal2.set(2023, 0, 1); int res = 0; while (cal.before(cal2)) { int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH); int day = cal.get(Calendar.DAY_OF_MONTH); String temp = year + ""; if (month < 9) { temp += "0" + (month + 1);//特别注意这里的月份是从0-11所以我们要加1 } else temp += (month + 1); if (day < 10) { temp += "0" + day; } else temp += day; //判断是否为顺子日期 for (int i = 0; i < temp.length() - 1; i++) { int count = 0;//每次换一个数都要吧原先的计数器清0 int a = Integer.parseInt(temp.charAt(i) + ""); for (int j = i + 1; j < temp.length(); j++) { int b = Integer.parseInt(temp.charAt(j) + ""); if (++a == b) { count++; if (count == 2) { res++; // System.out.print(temp+" "); 当不确定答案的时候可以打印出来看看 break; } } else break; } if (count == 2) break; } cal.add(Calendar.DATE, 1);//将日期加1 } System.out.println(res); } }