前言

本人是二本院校大二的计算机系学生,已经报名了下一届的蓝桥杯省赛,整个寒假学习了很多算法知识,我是看《算法很美》这个课程学习算法的,一套学习下来确实受益匪浅,视频在b站上面都有。

此前已经刷了两套真题,分别为:
2017年第八届蓝桥杯JavaB组省赛 刷题笔记、思路及答案
2016年第七届蓝桥杯JavaB组省赛 刷题笔记、思路及答案

注意:我是以我自身的水平来对题目进行分析的,所以可能代表了多数水平和我相当的朋友的观点,但不代表官方解法(特殊说明除外)。所以如果代码设计题有答案上的错误,还请各位大佬指正哈哈。接下来就来看看这次的第九届蓝桥杯JavaB组省赛的刷题笔记、思路及答案。

刷题笔记

第一题:第几天(已完成)
第二题:方格计数(已完成)
第三题:复数幂(已完成)
第四题:测试次数
第五题:快速排序(已完成)
第六题:递归三元组(已完成)
第七题:螺旋折线(已完成)
第八题:日志统计(已完成)
第九题:全球变暖(已完成)
第十题:堆的计数

第一题:第几天(已完成)

【题目】

2000年的1月1日,是那一年的第1天。
那么,2000年的5月4日,是那一年的第几天?注意:需要提交的是一个整数,不要填写任何多余内容。

【思路】

第一题往往是送分题,这个计算时间的题目可以有很多种解法。

1、简单粗暴法:

2000年是闰年,2月有29天,1月、3月、4月分别是:31天、31天、30天。因此总天数是31+29+31+30+4 = 125天

2、excel快速计算:

我是用excel计算的,excel对于日期时间等功能的计算非常的方便,在A1格子写上末尾日期,然后A2写上初始日期,然后写公式让两个格子相减,即能获得天数。如下图:


值得注意的是,关于两个数值的相减,一定要检查看看结果有没有多1或少1,为了测试excel减法的情况,我们举个例子:

很明显,第一天如果是1月1日,那么1月3日应该是第3天,也就是说excel计算出来的答案需要+1,也就是正确答案为125.

3、编程法:

还得写一个for循环,判断日期,判断闰平年,多麻烦,还不如以上两种方法计算,更简单精确。所以这里就不演示编程法了。

【正确答案】

125

第二题:方格计数(已完成)

【题目】

如图p1.png所示,在二维平面上有无数个1x1的小方格。我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。
你能计算出这个圆里有多少个完整的小方格吗?

【思路】

常规做法:

1、首先我们要简化问题,计算包含在圆圈内的格子数目,我们只需要计算以圆心为原点的坐标轴的第一象限(也就是1/4个圆内)的正方形个数即可,然后把算出来的结果×4即可。

2、然后使用两层for循环,遍历1/4圆中的每一个格子(遍历范围=半径×半径),利用勾股定理计算这个格子是否满足在圆内(如下图),也就是判断这个格子离圆心的最远距离L是否小于等于半径R(L=格子右上角那个点到圆心的距离)。如果满足,count++;

在上图中,红色箭头满足 :2² + 1² <= R² (R=3),因此这个格子在圆内,计数+1;
蓝色箭头不满足 :3² + 1² <= R²(R=3),因此这个格子不在圆内,继续下一次循环。

3、遍历完两层for循环,输出计数count*4即可。

优化做法:

这个做法是我仔细想了之后做出来的能减少for循环次数的方法,基本原理和上面的差不多。

1、还是只看1/4个圆,然后我们可以发现,黑色涂黑部分是一定在圆内的,这一部分可以直接算出来,而不用for循环一个个遍历,省下很多时间。

设黑色区域的边长为x,则一定满足 x² + x² < R²(从图上也能看出来),x < √(R²/2), 这里的√(R²/2)相对比x大一点点,大出来的这一点一定是小数部分,所以去掉小数部分,就是x的值。

2、随后我们只需遍历绿框所示的部分,大大减少了循环次数。实际上我们只需要计算其中一个绿框的部分然后×2即可。



3、count×4,就是最终结果。

【参考答案】

public class test
{public static void main(String[] args){Scanner sc = new Scanner(System.in);int r = sc.nextInt();//预计算,减少循环次数 r^2 = x^2+x^2 --> x = (int)√(r^2 / 2)int x = (int)Math.sqrt((r*r) / 2);   //一定在圆内的正方形格子边长int count = x*x;
//          System.out.println(x);//测试int y = 1;   //阶数,纵向指针int i = x + 1;    //横向指针,用于遍历(绿框内)每个格子//这个循环只是遍历绿框部分while(y <= x)    //i横向(向右)指针,y纵向(向上)指针,当y超过了绿框部分,就跳出循环{if(i*i + y*y <= r*r)    //关键语句,就算遍历了多余的格子,只要能进入这个判断,就能确定该格子是否在圆内。{count += 2;    //因为对称性(计算两个绿框部分)i ++;  //向右递增}else {y ++;  //向上递增i = x + 1;}}System.out.println(count*4);}
}

答案经过测试,和网上大佬的答案是相同的。

第三题:复数幂(已完成)

【题目】

设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。答案写成 "实部±虚部i" 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。

【思路】

首先这道题虽然只是计算123456次方,理论上说使用for循环执行123456也可以做出来,但是由于数据过于庞大,运行肯定会超时。所以需要尝试简化循环次数,所以考虑使用快速幂。如果不懂快速幂,建议百度学习一下,不难。简单来说就是使用递归、二分法来快速计算乘方。

此外,由于数据庞大,所以需要使用BigInteger类,BigInteger类可以表示无限大的整数。

另外计算复数的乘方时,要把虚部和实部分开来算,怎么分开算?其实很简单:

 (a + bi)*(c + di) = ac +adi + bci - bd
=(ac - bd)+(ad + bc)i

两个复数相乘,复数A的实部a,虚部b,复数B的实部c,虚部d,相乘后,得到新的复数C的实部(ac - bd),虚部(ad + bc)。

实部和虚部用一个数组存储即可,这个数组就是代表了这个复数。

【参考答案】

package test;import java.math.BigInteger;public class A3
{static BigInteger[] ini = {new BigInteger("2"), new BigInteger("3")};//快速幂,计算a^npublic static BigInteger[] quick(BigInteger[] a, int n){if(n == 1)return ini;if(n % 2 == 0)   //如果n是偶数,返回a^(n/2) * a^(n/2)return mul(quick(a, n / 2), quick(a, n / 2));else  //如果n是奇数,返回a^(n/2) * areturn mul(quick(a, n - 1), ini);}//两个复数相乘,返回新的复数public static BigInteger[] mul(BigInteger[] a, BigInteger[] b){//                 shi = a[0] * b[0] - a[1] * b[1]
//                  xu = a[0] * b[1] + a[1] * b[0] BigInteger[] t = new BigInteger[2];t[0] = a[0].multiply(b[0]).subtract(a[1].multiply(b[1]));t[1] = a[0].multiply(b[1]).add(a[1].multiply(b[0]));return t;}public static void main(String[] args){BigInteger[] one = quick(ini, 123456);    //计算ini的123456次方System.out.printf("%d%di",one[0],one[1]);}
}

代码经过测试,与网上的答案一致。

由于已经提前知道最终结果的实部和虚部都是负数,所以直接打印("%d%di")即可。如果说虚部是正数,才需要打印("%d+%di")。

第四题:测试次数(未完成)

【题目】

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n为了减少测试次数,从每个厂家抽样3部手机参加测试。某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?请填写这个最多测试次数。注意:需要填写的是一个整数,不要填写任何多余内容。

【思路及答案】

目前还是看不懂题目,建议参考下面大佬的文章。这道题实际上是leetcode里的原题,名字叫“鸡蛋掉落”。等弄懂了题目我再写出思路。

LeetCode 鸡蛋掉落(最清晰的解法)

第五题:快速排序(已完成)

【题目】

以下代码可以从数组a[]中找出第k小的元素。  它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。请仔细阅读分析源码,填写划线部分缺失的内容。import java.util.Random;
public class Main{public static int quickSelect(int a[], int l, int r, int k) {Random rand = new Random();int p = rand.nextInt(r - l + 1) + l;int x = a[p];int tmp = a[p]; a[p] = a[r]; a[r] = tmp;int i = l, j = r;while(i < j) {while(i < j && a[i] < x) i++;if(i < j) {a[j] = a[i];j--;}while(i < j && a[j] > x) j--;if(i < j) {a[i] = a[j];i++;}}a[i] = x;p = i;if(i - l + 1 == k) return a[i];if(i - l + 1 < k) return quickSelect( _________________________________ ); //填空else return quickSelect(a, l, i - 1, k);    }public static void main(String args[]) {int [] a = {1, 4, 2, 8, 5, 7};System.out.println(quickSelect(a, 0, 5, 4));}
}

【思路及答案】

我写的太长了,就另写了一篇博客来解这道题:
蓝桥杯第九届 javaB组省赛 第五题 快速排序(详解每行代码)

第六题:递归三元组(已完成)

【题目】

给定三个整数数组
A = [A1, A2, ... AN],
B = [B1, B2, ... BN],
C = [C1, C2, ... CN],
请你统计有多少个三元组(i, j, k) 满足:1. 1 <= i, j, k <= N
2. Ai < Bj < Ck  【输入格式】
第一行包含一个整数N。
第二行包含N个整数A1, A2, ... AN。
第三行包含N个整数B1, B2, ... BN。
第四行包含N个整数C1, C2, ... CN。对于30%的数据,1 <= N <= 100
对于60%的数据,1 <= N <= 1000
对于100%的数据,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000 【输出格式】
一个整数表示答案【输入样例】
3
1 1 1
2 2 2
3 3 3【输出样例】
27

【思路】

这里我用了类似于动态规划的做法。一定要先读懂题目的意思,题目的意思是说,在三行数据中,每行取一个,取出的这三个数字 (Ai,Bj,Ck ) 连起来时应满足 (Ai < Bj < Ck) ,那么这就是一个符合条件的三元组,然后题目要求找出这些三元组的个数。

1、先处理第二、三行:

我们先把第二三行处理,即先找出Bj < Ck的情况。

此时我们主要看第二行的数据,我们的任务是先列出第二行中每个元素的情况数(情况数:当我第二行选择了某个元素时,第三行有多少个元素符合情况)。拿输入样例举例:

【1 1 1】
【2 2 2】
【3 3 3】

我们先定义一个数组s2,这个数组用于记录第二行的情况数。然后在第二行定义指针p=0, 这个指针是向右扫描的。(以下"[ ]"符号代表该行的指针所在位置)

此时p=0,第二行对应的元素是2,那么当这个元素是2时,第三行有几个元素满足条件呢?可以发现,第三行全部元素都是3,而2 < 3满足条件,所以说,在只看第二、三行的情况下,且p=0时,情况数有3个,然后把这个记录存到刚刚定义的数组s2,即s2[p] = 3

【 1  1 1】
【[2] 2 2】   p=0        s2【3,?,?】
【 3  3 3】

同理,当p=1时,对应的元素是2,在第三行也有3个元素满足条件,因此s2[1] = 3; 再同理,p=2时,s2[2] = 3

【 1  1 1】
【 2 [2]2】       p=1        s2【3,3,?】
【 3  3 3】【 1 1  1 】
【 2 2 [2]】  p=2        s2【3,3,3】
【 3 3  3 】

至此,第二行的情况数已记录完成,s2 = 【3,3,3】,这个数组代表的意思是,当我第二行选择了其中的第 i 个元素,这个元素后续的情况有s2[i]种。

2、然后处理第一、二行:

处理第一、二行,先定义一个数组s1,用于记录第一行的情况数(和上面的第二行类似)。那么就需要在第一行中定义一个指针p=0(q是第二行指针):

【[1] 1 1】    p=0        s1【?,?,?】
【 2  2 2】       q=0
【 3  3 3】

比如当我第一行选了第一个元素(p=0)时,然后我再在第二行选第1个元素。之前已经计算过,当第二行选择了第1个元素后,后面有3种情况,所以,在第一行是1(p=0)、第二行是2(q=0)的前提下,这种情况有3种。

同理,在第一行是1(p=0)、第二行是2(q=1)的前提,情况有3种。

再同理,在第一行是1(p=0)、第二行是2(q=2)的前提,情况有3种。

综上,第一行是1(p=0)的情况下,一共有3+3+3=9种情况,数组s1[0] = 9;
s1[0] = 9的意思是,当我第一行选了第一个元素,后续情况就有9种。

【[1] 1 1】    p=0        s1【9,?,?】
【 2  2 2】
【 3  3 3】

同理,第一行是1(p=1)的情况下,一共有3+3+3=9种情况,数组s1[1] = 9;

【 1 [1]1】    p=1        s1【9,9,?】
【 2  2 2】
【 3  3 3】

再同理,p=2,数组s1[2] = 9;

【 1 1 [1]】   p=2        s1【9,9,9】
【 2 2  2 】
【 3 3  3 】

至此,第一行的情况数已记录完成,s1 = 【9,9,9】,这个数组代表的意思是,当我第一行选择了其中的第 i 个元素,这个元素后续的情况有s1[i]种。

3、计算总个数

现在题目的问题就可以简化成:第一行所有元素的情况数之和。

很显然,数组s1的和,就是答案。明白了思路再写代码就容易了。

【参考答案】

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;public class A6
{public static void main(String[] args){Scanner sc = new Scanner(System.in);int N = sc.nextInt();int[][] arr = new int[N][N];int[] arr1 = new int[N];       //第一行for(int i = 0; i < N; i++)arr1[i] = sc.nextInt();int[] arr2 = new int[N];      //第二行for(int i = 0; i < N; i++)arr2[i] = sc.nextInt();int[] arr3 = new int[N];      //第三行for(int i = 0; i < N; i++)arr3[i] = sc.nextInt();//排序Arrays.sort(arr1);Arrays.sort(arr2);Arrays.sort(arr3);//上面一堆都是初始化数组,接下来正式进入思路代码//       int[] s1 = new int[N];  //记录第一行每个数字的情况数int[] s2 = new int[N]; //记录第二行每个数字的情况数int sum1 = 0;   //用于记录s1数组的总和,其实就是最终答案。int sum2 = 0;    //用于记录s2数组的总和int p1 = 0, p2 = 0, p3 = 0; //三行指针//先处理第二、第三行while(p2 < N && p3 < N){/*比如:【 1,  2, 4, 5】  Ai【[3], 4, 6, 9】  Bj【2, [5], 7, 9】  Ck  p3=1当第二行选择“3”时,在第三行找到第一个比它大的数“5”,记录其位置p3=1那么5后续的数都满足条件(前提是数组排好序),因此情况数是N-p3*/if(arr2[p2] < arr3[p3])     //第二行的起始数小于第三行的起始数(不能等于!题目要求){s2[p2] = N - p3;sum2 += s2[p2];p2 ++;}else{p3 ++;}}p2 = 0;   //初始化//处理第一、二行while(p1 < N && p2 < N){//第一行的起始数小于第二行的起始数if(arr1[p1] < arr2[p2])    {sum1 += sum2;    //直接相加,可以不用s1数组p1 ++;}else{/*sum2本来就是s2的总和,最好的情况就是s2所有元素都能参与,比如:  【1,2,3】                   【1,     2,    3   】【2,3,4】  用s2记录后-->    【(2,3),(3,2), (4,1)】     -->    sum2 = 3+2+1=6【3,4,5】                   (k,v)--> (元素k,该元素的情况数v)综上,当第1行是“1”时,第二行所有元素都能参与,情况数就是6当第1行是“2”时,第二行就不是全部元素参与了,而会丢掉(2,3)这个元素,此时的情况数是2+1,这个和sum2-s2[0](3+2+1 - 3)得到的是一样的,就是减去前缀的意思。*/sum2 -= s2[p2];  //减去前缀p2 ++; //指针后移}}System.out.println(sum1);}
}

第七题:螺旋折线(已完成)

【题目】

如图p1.pgn所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。  例如dis(0, 1)=3, dis(-2, -1)=9  给出整点坐标(X, Y),你能计算出dis(X, Y)吗?【输入格式】
X和Y 对于40%的数据,-1000 <= X, Y <= 1000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000  【输出格式】
输出dis(X, Y)  【输入样例】
0 1【输出样例】
3

【思路】

首先化简一下思路,在螺旋的路线中,把图中画 “X” 的线段旋转到下方,使得红色线段可以围成一个正方形。每一层都照这种做法,就会得到很多个嵌套的正方形。每一层正方形的起点和终点都是左下角的坐标(拿第一层举例,原来起始点坐标应该是在 (0,0) ,经过旋转变化后,起始点就到了 (-1,-1)


举例,如下图所示,目标坐标在(2,2),目标坐标所在层数是2,所以必定要加上第一层的距离(为8)。然后计算第二层的距离:

x轴距离:目标坐标横坐标 - 起始坐标横坐标 = 2 - ( -2 ) = 4
y轴距离:目标坐标纵坐标 - 起始坐标纵坐标 = 2 - ( -2 ) = 4

横纵坐标差之和 = x 轴距离 + y 轴距离

所以总距离 = 第一层距离数 + 横纵坐标差之和 = 16, 也就是蓝色箭头个数之和。

但是很显然,上面计算距离的公式是不完整的。比如下面图示的情况,当目标坐标为(2,0) 时,上面公式就得不出正确答案。

因此我们要换一种思路,即反向计算(绿色箭头)。仍然先计算目标坐标与起始坐标的横纵坐标差之和

横坐标之差 = 2 - ( -2 ) = 4
纵坐标之差 = 0 - ( -2 ) = 2
横纵坐标差之和 = 6

这里计算的横纵坐标差之和绿色箭头的距离,所以总距离 = 第二层距离数 - 横纵坐标差之和 = 24 - 6 = 18. 这里要注意【第二层距离数】包括了【第一层距离数】

【参考答案】

package _9s_LanQiao;import java.util.Scanner;public class A7
{public static void main(String[] args){Scanner sc = new Scanner(System.in);int X = sc.nextInt();int Y = sc.nextInt();int n = Math.max(Math.abs(X), Math.abs(Y));   //该点所在的层数/** 第1层 = 2*4 = 8* 第1+2层 = 2*4 + 4*4 = 24* 第1+2+3层 = 2*4 + 4*4 + 6*4 = 48* 第1+...+n-1层 = 8*(1+2+..+n-1) = 4n(n-1)* 第1+...+n层 = 8*(1+2+..+n) = 4n(n+1)*/long sum_n = 4 * n * (n + 1);       //第n层完整正方形long sum_n_1 = 4 * n * (n - 1);  //第n-1层完整正方形long sum = 0; //总距离//先计算【目标坐标与起始坐标】的横纵坐标差,计算总距离(横纵坐标差之和):int x_x = X - (-n);int y_y = Y - (-n);int xy = x_x + y_y;     //总距离(横纵坐标差之和)//如果目标坐标落在了正方形左侧、上侧:if((-n <= Y && Y <= n && X == -n) || (-n <= X && X <= n && Y == n))sum = sum_n_1 + xy;//如果目标坐标落在了正方形右侧、下侧:if((-n <= Y && Y <= n && X == n) || (-n <= X && X <= n && Y == -n))sum = sum_n - xy;System.out.println(sum);}
}

时间复杂度O(1),代码可以更简洁。

第八题:日志统计(已完成)

【题目】

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:ts id  表示在ts时刻编号id的帖子收到一个"赞"。  现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。  具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。  给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。  【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。  对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000  【输出格式】
按从小到大的顺序输出热帖id。每个id一行。  【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3  【输出样例】
1
3

【思路】

1、读题:

在输入样例中,输入的格式是【时间点ts+帖子号id】,这一行表示帖子号为id的帖子在时间点ts收获了一个赞

然后输入的【参数D】是指一段时间,【参数K】是指在这段时间D内,如果点赞数不少于K,则这个帖子是热帖

用图片讲述一下题目所表达的意思:

图中数轴的值(黑色数字)代表时间点ts,红色数字代表帖子的id。所以数值上每个点都表示了该帖子在该时间点收获了一个点赞。那么如何判断帖子是否是热帖?那就看一个时间段D内,该帖子是否被点赞了K次。我们假设K = 3,D = 4


假设这个时间段D的起点和数轴的起点相同,那么这个时间段D中,帖子1被点赞了1次,帖子2被点赞了2次。(不包括帖子3,因为题目说了这个时间段区间是左闭右开区间),由于没有一个帖子点赞数大于等于K(K=3),所以这个时间段内没有热帖。

按照题目的意思,这个时间段是可以任意移动的,比如我可以移动到如下图:


在这个时间段中,帖子2被点赞了2次,帖子3被点赞了1次。

然后我们把时间段移动到一个比较巧妙的位置:


这种情况,很明显帖子2被点赞了3次,满足热帖的条件(因为K=3),因此,帖子2是热帖。

2、代码实现

根据上面的思路,我们只需要得到某个帖子所有的时间点,然后用时间段一个个去比较,如果时间段内存在K个及以上的时间点,那这个帖子就是热帖了。

我还是参考了一下网上大佬的代码才做出来的。当我看到下面这段代码时,我就知道应该怎么做了:

Map<Integer, List<Integer>> map = new HashMap<>();

创建map集合,key是帖子的id,value是一个list集合,用于存放该帖子id的所有时间点。

【参考答案】

package _9s_LanQiao;import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;/**
第一行包含三个整数N、D和K。     N帖子数,D时间段,K热帖点赞不少于该数【输入样例】
ts id
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3  【输出样例】
1
3  */
public class A8
{public static void main(String[] args) {Map<Integer, List<Integer>> map = new HashMap<>();Scanner sc = new Scanner(System.in);int N = sc.nextInt();int D = sc.nextInt();int K = sc.nextInt();for(int i = 0; i < N; i++){int ts = sc.nextInt();   //时间点int id = sc.nextInt();    //帖子号List<Integer> list = new ArrayList<>();if(!map.containsKey(id))   //如果hashmap没有这个id{list.add(ts);}else    //如果有这个id,拿出列表,添加值进去{list = map.get(id);list.add(ts);}map.put(id, list);}for(Map.Entry<Integer, List<Integer>> entry : map.entrySet())   //为了拿到key和value{//entry.getKey()可拿到键k,entry.getValue()可拿到值vList<Integer> list = entry.getValue();Collections.sort(list);  //拿出这个帖子的所有时间点,排序for(int i = 0; i < list.size() - K + 1; i++){//拿时间段D去比较,就是用上面提到的思路,满足条件就输出id即可。//这里我的思路是:如果从第i个时间点开始,往下的第K-1个时间点与第i个时间点之差 如果小于时间段D,那这个帖子就是热帖。//也就是说时间段D内存在大于等于K个的时间点,那这个帖子就是热帖。if(list.get(i + K - 1) - list.get(i) < D)           //[0,9] D=10, K=2{System.out.println(entry.getKey());break;}}}}
}

第九题:全球变暖(已完成)

【题目】

你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:.......
.##....
.##....
....##.
..####.
...###.
.......其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。  由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。  例如上图中的海域未来会变成如下样子:.......
.......
.......
.......
....#..
.......
.......请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。  【输入格式】
第一行包含一个整数N。  (1 <= N <= 1000)
以下N行N列代表一张海域照片。  照片保证第1行、第1列、第N行、第N列的像素都是海洋。  【输出格式】
一个整数表示答案。【输入样例】
7
.......
.##....
.##....
....##.
..####.
...###.
.......  【输出样例】
1

【思路】

先理解一下题目的意思(我之前由于没有理解题目意思,思路和代码全错了,所以看懂题很重要!!!):

‘ . ’是海洋,’ # ‘是陆地。题目给定一个岛屿图,经过变化后,只要“陆地”的上下左右有一个是“海洋”,那么这块“陆地”就会被淹没(变成’ . ')

判断一块区域是不是岛屿:“陆地”的上下左右连在一起的一片陆地就是一块岛屿。

随后通过dfs,把相连的“陆地”都标记为“1”,把不会淹没的“陆地”标记为“2”,由于进行一次dfs查找的范围就是一块岛屿,所以如果这块岛屿出现了“2”标记,说明这块岛屿还存在,没有被完全淹没。

【参考答案】

import java.util.Scanner;/**
7
.......
.##....
.##....
....##.
..####.
...###.
..............
.......
.......
.......
....#..
.......
.......*/public class A9
{//定义方向,上右下左static int[][] d = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};static int x = 0, y = 1;        //只是为了方便直观static boolean stay = false; //这块岛屿是否能留下来?先初始化为不能留下来。 static int count = 0;          //计算有多少个岛屿沦陷了//打印地图,方便测试public static void print(int[][]map){for(int i = 0; i < map.length; i++){for(int j = 0; j < map[0].length; j++){System.out.print(map[i][j]);}System.out.println();}}public static void dfs(char[][] map, int[] node, int[][] book){//只要进来dfs了,坐标node就一定是陆地,把他标记成1book[node[x]][node[y]] = 1;//定义flag,初始化为true,意思是默认当前的node的上下左右都是“陆地”。boolean flag = true;//四个方向走一遍for(int i = 0; i < 4; i++){//下一个结点int[] next = new int[] {node[x] + d[i][x], node[y] + d[i][y]};//如果这个方向的像素仍然是陆地且dfs没有走过if(map[next[x]][next[y]] == '#' && book[next[x]][next[y]] == 0)dfs(map, next, book); //下一节点进行dfsif(map[next[x]][next[y]] == '.')flag = false;   //只要node有一个方向有水,它就留不下来,flag记为false}//如果flag是true,说明这个节点node上下左右都是陆地,那它就不会被淹没,记为2if(flag){book[node[x]][node[y]] = 2;stay = true;   //这块岛屿留下来了。}}public static void main(String[] args){Scanner sc = new Scanner(System.in);int n = sc.nextInt();     //地图边长String[] t = new String[n];Scanner sc2 = new Scanner(System.in);for(int i = 0; i < t.length; i++)t[i] = sc2.nextLine();char[][] is = new char[n][n];    //岛屿平面地图for(int i = 0; i < n; i++){char[] temp = t[i].toCharArray();for(int j = 0; j < n; j++)is[i][j] = temp[j];}//上面一大串都是为了得到地图的二维数组,下面开始正式dfsint[][] book = new int[n][n]; //标记数组for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(is[i][j] == '#' && book[i][j] == 0)    //如果发现了一块"新"陆地,且这个地方没有走过(没有标记成1或2){stay = false;    //初始化int[] node = new int[] {i, j};    //就把当前节点(坐标)传入dfsdfs(is, node, book);if(!stay)    //如果岛屿没有留下来,计数count ++;}}}
//      print(book);System.out.println(count);}
}

第十题:堆的计数(待完成)

【题目】


标题:堆的计数我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树。
每个节点有一个权值。对于小根堆来说,父节点的权值一定小于其子节点的权值。  假设N个节点的权值分别是1~N,你能求出一共有多少种不同的小根堆吗?  例如对于N=4有如下3种:1/ \2   3/
41/ \3   2/
41/ \2   4/
3由于数量可能超过整型范围,你只需要输出结果除以1000000009的余数。  【输入格式】
一个整数N。
对于40%的数据,1 <= N <= 1000
对于70%的数据,1 <= N <= 10000
对于100%的数据,1 <= N <= 100000【输出格式】
一个整数表示答案。  【输入样例】
4  【输出样例】
3

【思路及答案】

我看网上大佬的答案,用到了逆元、动态规划等,太难了……还是等到会做了再写吧。

2018年第九届蓝桥杯 JavaB组省赛 刷题思路及答案相关推荐

  1. 2018第九届蓝桥杯JavaB组省赛真题及详解

    2018第九届蓝桥杯JavaB组省赛真题及详解 第一题:第几天 第二题:方格计数 第三题:复数幂 第四题:测试次数 第五题:快速排序 第六题:递增三元组 第七题:螺旋折线 第八题:日志统计 第九题:全 ...

  2. 第九届蓝桥杯JavaB组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.第几天 题目描述 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数 ...

  3. 第十届蓝桥杯JavaB组省赛真题

    试题 A: 组队 本题总分:5 分 [问题描述] 作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分如下表所示. ...

  4. 2018第九届蓝桥杯JavaA组省赛真题详解

    目录 第一题:分数 第二题:星期一 第三题:复数幂 第四题:方格计数 第五题:打印图形 第六题:航班时间 第七题:三体攻击 第八题:全球变暖 第九题:倍数问题 第十题:付账问题 题解待更新 第一题:分 ...

  5. 2018年第九届蓝桥杯A组省赛

    A.分数(5分) 答案:1048575/524288 试题 A: 分数 本题总分:5 分 [问题描述] 1/1 + 1/2 + 1/4 + 1/8 + 1/16 + - 每项是前一项的一半,如果一共有 ...

  6. 2018年第九届蓝桥杯B组 国赛

    一.换零钞 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可. X 星球的钞票的面额只有:100 元,5 元,2 元,1 元,共 4 种. 小明去 X 星旅游,他手里只 ...

  7. 2017年第八届蓝桥杯JavaB组省赛 刷题笔记、思路及答案

    前言 本人是二本院校大二的计算机系学生,已经报名了下一届的蓝桥杯省赛,整个寒假在家(这次的寒假挺久的哈哈)在b站学习了一些算法(现在会bfs走迷宫.dfs相关算法.递归回溯.常见排列算法),但是还是有 ...

  8. 2019蓝桥杯Java决赛题答案_2019第十届蓝桥杯JavaB组省赛真题详解

    目录 题解待更新 第一题:组队 题目描述 做为篮球队教练,你须要从如下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分以下表所示.请你计算 ...

  9. 第六届蓝桥杯JavaB组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.三角形面积 题目描述 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何 ...

最新文章

  1. 阿里巴巴Java开发手册终极版
  2. .NET的一点历史故事:擦肩而过的机遇
  3. int *p = *******a是什么鬼?
  4. 揭秘阿里云 RTS SDK 是如何实现直播降低延迟和卡顿
  5. android toolbar源码解析,深入理解Android 5.0中的Toolbar
  6. postman使用之四:设置读取变量和切换环境
  7. CF gym101933 K King's Colors——二项式反演
  8. MySQL MHA详解(一)——基本原理
  9. Illustrator 教程,如何在 Illustrator 中创建和编辑图层?
  10. Electron IPC(进程间通信)之ipcMain和ipcRenderer
  11. 如何加载和保存AutoCAD DXF文件(四参数法)
  12. 怎么对文件夹名称进行编号排序
  13. 2.6 Abbreviation( 缩 写)
  14. autoproxy插件下载 linux,AutoProxy 0.29.6
  15. liunx 中文乱码 和 html转图片中文乱码问题处理方式以及linux中文字体包
  16. win10家庭版升级win10专业版输入产品密钥的后成了企业版且无法激活求解????
  17. 基于SIFT+Kmeans+SVM的场景识别,参数需注意的问题(Matlab实现)
  18. Jetson NX设置nvme固态硬盘为系统盘
  19. mybatis-plus使用updateById更新数据不生效,需要使用lambdaUpdate
  20. EMV技术学习和研究(二)应用选择

热门文章

  1. 打印机form2尺寸_注册您的Form 2打印机,享受更多福利!
  2. 充分激发自己的内在潜能
  3. python之不同公司不同年份同一财务指标比较(柱状图)
  4. freemarker导出word文档对图片拉伸或拉长的处理
  5. Windows API函数大全(方便查找)
  6. 算法学习笔记----用动态规划解决钢管切割问题
  7. 金蝶ERP K3 介绍
  8. windows找不到文件 pythonw
  9. 甲乙两列客车的长分别为150m和200m,它们相向行驶在平行的轨道上,已知甲车上某乘客测得乙车在他窗口外经过的时间为10秒,那么,乙车上的乘客看见甲车在他窗口外经过的时间是()
  10. 内存泄漏检测C版小工具