本篇博客旨在整理记录自己刷的一些蓝桥杯训练题的思路、代码以及注解,同时希望可给小伙伴一些帮助。本人也是算法小白,水平有限,如果文章中有什么错误之处,希望小伙伴们可以在评论区指出来,共勉 。
题目
:语预备爷gzp是个逗(tu)比(hao),为了在即将到来的英语的quiz中不挂科,gzp废寝忘食复习英语附录单词表,俨然一场人间悲剧。不过上天有好生之德,上帝扔给了gzp一张纸,上面记载了将要考到的单词。不过gzp是个逗比,之前复习的东西全忘记了,所以他又要再来一次复习。不过已经知道了要考的单词,所以不需要复习单词表的所有页数。因此,现在需要你帮助他求出有多少页纸需要复习。他会告诉你每个单词会在哪几页出现,并且告诉你要考哪些单词,你只要告诉他答案就可以了。由于一个单词会出现在不同页上,只需要复习在最前面一页上的就可以了。
输入格式:
第一行一个整数n,表示单词附录有n个单词。接下来n行每行一个小写字母组成的单词和一个整数,表示某一个单词和它所在的页数。接下来是一行整数m,表示要考m个单词,接下来m行小写字母组成的单词,表示要考到的单词。
输出格式:
一个数,表示需要复习的页数
输入输出样例:
输入:
5
ab 1
ac 2
ab 2
ac 3
c 3
3
ab
ac
c
输出:
3
数据规模和约定: 0 <= n,m <= 100000,单词长度 <= 10。
解题代码:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
// 创建 Set 集合用来保存需要复习的页数
Set<Integer> set = new HashSet<>();
// 单词表中单词的录入
int n = s.nextInt();
Map<String, Integer> map = new HashMap<>();
for (int i = 0;i < n; i++) {
// 录入单词以及所在的页数
String key = s.next();
int value = s.nextInt();
// 这里判断 key 是否出现,如果没出现过直接保存到单词表,如果出现过判断 value 值,保存小的那个
// containsKey() 方法检查 hashMap 中是否存在指定的 key 对应的映射关系。存在返回true
if (!map.containsKey(key)) {
map.put(key, value);
} else {
if (map.get(key)>value) {
map.put(key, value);
}
}
}
// 录入需要考试的单词
int m = s.nextInt();
String[] str = new String[m];
for (int i = 0; i < m; i++) {
// 输入要考试的单词
str[i] = s.next();
// 判断这个单词是否在单词表中
if (map.containsKey(str[i])) {
// 如果在单词表中则把单词对应的 value 值保存到 Set 中去
set.add(map.get(str[i]));
}
}
// 调度 size 方法得到需要复习的页数
System.out.println(set.size());
}
}
题目
:乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊 C 型饮料,凭 3 个瓶盖可以再换一瓶 C 型饮料,并且可以一直循环下去(但不允许暂借或赊账)。
请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的 n 瓶饮料,最后他一共能喝到多少瓶饮料。
输入格式:
输入一个整数 n(0 < n < 1000),表示开始购买的饮料数量。
输出格式:
输出一个整数,表示实际得到的饮料数
输入输出样例:
输入
100
输出
149
运行限制:
解题代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int num = n;
while (n/3 != 0){
num += n / 3;
n = (n%3) + (n/3);
}
System.out.println(num);
}
}
题目
:一般来说,一个正整数可以拆分成若干个正整数的和。
例如,1=1,10=1+2+3+41=1,10=1+2+3+4 等。对于正整数 n 的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,n 被分解为了若干个不同的 22 的正整数次幂。注意,一个数 x 能被表示成 22 的正整数次幂,当且仅当x 能通过正整数个 22 相乘在一起得到。
例如,10=8+2=23+2110=8+2=23+21是一个优秀的拆分。但是,7=4+2+1=22+21+207=4+2+1=22+21+20 就不是一个优秀的拆分,因为 11 不是 22 的正整数次幂。
现在,给定正整数n,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。
输入格式:
输入只有一行,一个整数 n (1≤n≤107),代表需要判断的数。
输出格式:
如果这个数的所有拆分中,存在优秀的拆分。那么,你需要从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。可以证明,在规定了拆分数字的顺序后,该拆分方案是唯一的。
若不存在优秀的拆分,输出 -1
。
输入输出样例:
输入
6
输出
4 2
运行限制:
解题代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
// 奇数直接输出-1即可结束
if (n % 2 != 0) {
System.out.println(-1);
return ;
}
// 对于偶数的情况,找到2的k次方小于n,且k最大
while (n != 0){
n = f(n);
}
}
private static int f(int n) {
int res = 1;
while (Math.pow(2, res) <= n) {
res++;
}
System.out.println((int)Math.pow(2, res-1) + " ");
return n - (int)Math.pow(2, res - 1);
}
}
题目
:小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入格式:
一个日期,格式是 “AA/BB/CC" (0≤A,B,C≤9)。
输出格式:
输出若干个不相同的日期,每个日期一行,格式是 “yyyy−MM−dd”。多个日期按从早到晚排列。
输入输出样例:
输入
02/03/04
输出
2002-03-04
2004-02-03
2004-03-02
运行限制:
解题代码:
import java.util.*;
public class Main {
public static void one(int y,int m,int d){
int year=y+(y<60?2000:1900);
month[1]=((year%4==0&&year%100!=0)||year%400==0)?29:28;
if(m<13&&m>0&&d>0&&d<=month[m-1]){
System.out.println(year+"-"+(m<10?"0"+m:m)+"-"+(d<10?"0"+d:d));
}
}
public static int month[]={31,28,31,30,31,30,31,31,30,31,30,31};
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s=sc.next();
String ss[]=s.split("/");
int arr[]=new int[3];
for(int i=0;i<3;i++){
arr[i]=Integer.valueOf(ss[i]);
}
one(arr[0],arr[1],arr[2]);
one(arr[2],arr[0],arr[1]);
one(arr[2],arr[1],arr[0]);
}
}
题目
:2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。
输入格式:
输入包含一个八位整数N,表示日期。
对于所有评测用例,10000101 ≤ N ≤ 89991231,保证N 是一个合法日期的 8 位数表示。
输出格式:
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。
输入输出样例:
输入
20200202
输出
20211202
21211212
运行限制:
解题代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String date = sc.next();
// 用于判断第一个回文是否已经输出
// 因为在第一个回文和第一个ABAB之间可能还存在若干个回文,这些回文我们不输出
int key = 0;
// 因为不知道下一个回文日期,所以定义一个死循环,遇到回文日期再break
while (true) {
while (true) {
// 日期自加
date = AddDate(date);
// 输出下一个回文
if (isHuiWen(date)) {
if (key == 0) {
System.out.println(date);
key++;
break;
} else {
break;
}
}
}
if (isABAB(date)) {
System.out.println(date);
break;
}
}
}
// 判断回文
public static boolean isHuiWen(String date) {
// 回文日期,就是日期反转后,与原来的日期相等
return date.equals(new StringBuffer(date).reverse().toString());
}
// 判断ABAB -- 在回文日期的基础上判断,节约时间
public static boolean isABAB(String date) {
// 转换成字符数组
char[] c = date.toCharArray();
// ABAB型,第一个字符和第三个字符相等,第二个字符与第四个字符也相等
if(c[0] == c[2] && c[1] == c[3]) {
return true;
}
return false;
}
// 日期自加
public static String AddDate(String date) {
// 转换成整型
int d = Integer.parseInt(date);
// 分离年月日
int year = d / 10000;int month = d% 10000 / 100; int day = d % 100;
int[] arr = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 判断平年闰年
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
arr[1] = 29; // 闰年二月有29天
} else {
arr[1] = 28; // 平年二月有28天
}
day++;
if (day > arr[month - 1]) {
month++;
day = 1;
}
if (month > 12) {
year++;
month = 1;
}
return year*10000+month*100+day + "";
}
}
题目
:共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式:
一行两个正整数n和m
输出格式:
一个实数P表示答案,保留4位小数。
输入输出样例:
输入
2 3
输出
0.7500
数据规模和约定: 1 ≤ n,m ≤ 20
解题代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt(),m = s.nextInt();
// 设置初始化
double arr[][] = new double[m+1][n+1];
double p = 1.0/n;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (i < j) {
// 当 图案数量 > 购买印章,集齐的概率为 0
arr[i][j] = 0;
}
if (j == 1) {
// 当 图案数量为 1 时,集齐的概率为购买印章数量的次方
arr[i][j] = Math.pow(p, i-1);
} else {
// DP 的状态方程
arr[i][j] = arr[i-1][j-1]*(n-j+1)*p + arr[i-1][j]*(j*p);
}
}
}
System.out.printf("%.4f",arr[m][n]);
}
}
题目
:有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式:
第一行输入一个正整数n。
以下n行描述该方格。金币数保证是不超过1000的正整数。
输出格式:
最多能拿金币数量。
输入输出样例:
输入
3
1 3 3
2 2 2
3 1 2
输出
11
数据规模和约定: n <= 1000
解题代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int a[][] = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = s.nextInt(); // a数组用来存放每个格子的金币数
}
}
int dp[][] = new int[n][n];
dp[0][0] = a[0][0]; // 第一个格子的最大值就是第一个格子的金币数
for (int i = 1; i < n; i++) {
dp[0][i] = dp[0][i-1] + a[0][i]; // 第一行因为每个格子的上面没有格子,所有只能加上左边格子的金币总数量
dp[i][0] = dp[i-1][0] + a[i][0]; // 第一列因为每个格子的左边没有格子,所以只能加上上面格子的金币总数量
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]) + a[i][j]; // 加上上面格子和左边格子更大的金币数
}
}
System.out.println(dp[n-1][n-1]); // 最后一个即是n*n个格子的最大值
}
}
题目
:24点游戏是一个非常有意思的游戏,很流行,玩法很简单:给你4张牌,每张牌上有数字(其中A代表1,J代表11,Q代表12,K代表13),你可以利用数学中的加、减、乘、除以及括号想办法得到24,例如:
((A*K)-J)Q等价于((113)-11)*12=24
加减乘不用多说了,但除法必须满足能整除才能除!这样有一些是得不到24点的,所以这里只要求求出不超过24的最大值。
输入格式:
输入第一行N(1<=N<=5)表示有N组测试数据。每组测试数据输入4行,每行一个整数(1到13)表示牌值。
输出格式:
每组测试数据输出一个整数,表示所能得到的最大的不超过24的值。
输入输出样例:
输入
3
3
3
3
3
1
1
1
1
12
5
13
1
输出
24
4
21
运行限制:
解题代码:
import java.util.Scanner;
public class Demo04 {
static int N,vis[],arr[],max,pos;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//表示有N组数据,每组数据输入4行
N = sc.nextInt();
int[][] num = new int[N][4];
vis = new int[4];
arr = new int[4];
for (int i = 0; i < N; i++) {
for (int j = 0; j < 4; j++) {
num[i][j] = sc.nextInt();
}
}
for (int i = 0; i < N; i++) {
max = 0;
Dfs(1,num[i]);
System.out.println(max);
}
}
static int VF(int a,int b,int h){
switch (h){
case 1:
return a+b;
case 2:
return a-b;
case 3:
return a*b;
}
if (b == 0){
return 1000;
}
if(a % b != 0){
return 1000;
}
return a/b;
}
static void Dfs(int step, int[] num) {
for (int i = 0; i < 4; i++) {
if (vis[i] == 0){
vis[i] = 1;
arr[pos++] = num[i];
Dfs(step+1,num);
vis[i] = 0;
arr[--pos] = 0;
}
}
if (step > 4){
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
for (int k = 1; k <= 4; k++) {
int tp1,tp2,tp3;
tp1 = VF(arr[0],arr[1],i);
tp2 = VF(tp1,arr[2],j);
tp3 = VF(tp2,arr[3],k);
if(tp3 <= 24) max = Math.max(max, tp3);
tp1 = VF(arr[1],arr[2],j);
tp2 = VF(arr[0],tp1,i);
tp3 = VF(tp2,arr[3],k);
if(tp3 <= 24) max = Math.max(max, tp3);
tp1 = VF(arr[1],arr[2],j);
tp2 = VF(tp1,arr[3],k);
tp3 = VF(arr[0],tp2,i);
if(tp3 <= 24) max = Math.max(max, tp3);
tp1 = VF(arr[0],arr[1],i);
tp2 = VF(arr[2],arr[3],k);
tp3 = VF(tp1,tp2,j);
if(tp3 <= 24) max = Math.max(max, tp3);
tp1 = VF(arr[2],arr[3],k);
tp2 = VF(arr[1],tp1,j);
tp3 = VF(arr[0],tp2,i);
if(tp3 <= 24) max = Math.max(max, tp3);
}
}
}
}
}
}
对各位小伙伴有帮助的话,希望可以点赞❤️+收藏⭐,谢谢各位大佬~~