文章目录

  • 算法竞赛题目的类型
    • 核心代码模式
    • ACM模式
  • Java的输入与输出
    • 输入
      • 方式一:借助Scanner函数(输入数据量少推荐使用)
      • 方式二:使用BufferedReader函数(输入数据量大推荐使用,效率更高)
      • 实战选择案例
    • 输出
      • 方式一:采用System.out.printf()(输出数据量少可使用)
      • 方式二:采用PrintWriter(输出数据量大推荐使用)
      • 实战案例场景
  • Java读取文件
  • 常用集合类
    • 常用api
  • Java基本模板

算法竞赛题目的类型

主要分为核心代码模式以及ACM模式,前者就是只需要实现对应的功能函数关注函数传入的参数值以及我们需要返回的结果集即可,后者则需要我们从main方法开始完整的从读入开始截至最后的输出。

  • 核心代码模式:力扣。
  • ACM模式:蓝桥杯、ACM竞赛。

上案例题,斐波那契数列:

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。

核心代码模式

我们来看下力扣的一道题509. 斐波那契数:右边是已经给我们写好了的相应函数,我们只需要完成函数功能方法即可(函数名、结果类型、参数类型不能变,参数名称可以改):

  • 为什么参数名称可以改?因为你写完的程序发送到服务器,服务器会有一个事先写好的main方法去调用你这个fib()函数,这样你就可以想得通为什么参数名称是可以修改的了。

class Solution {public int fib(int n) {int[] dp = new int[33];dp[1] = 1;dp[2] = 1;for (int i = 3; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
}

ACM模式

相应竞赛:蓝桥杯

给出题目以及相应的输入、输出案例,然后不会给你任何代码,让你从头文件开始去写输入、功能函数以及最后的输出。

案例题我们来看Acwing网站上的 21. 斐波那契数列:所有的代码都需要自己去实现包括导包

import java.util.*;
import java.io.*;class Main {static long[] fn = new long[65];static int count, n;public static void main (String[] args)throws Exception {BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));count = Integer.parseInt(cin.readLine());while (count != 0) {n = Integer.parseInt(cin.readLine());//斐波那契递推fn[1] = 1;fn[2] = 1;for (int i = 3; i <= n; i++) fn[i] = fn[i - 1] + fn[i - 2];System.out.printf("Fib(%d) = %s\n", n, Long.valueOf(fn[n]));count--;}}
}


Java的输入与输出

输入

方式一:借助Scanner函数(输入数据量少推荐使用)

若是数据是固定的就几个推荐使用Scanner,因为比较方便可以直接使用nextInt()得到指定类型的值。

例如 1214. 波动数列:

输入格式
共一行,包含四个整数 n,s,a,b,含义如前面所述。

分析:类似于这种固定几个数字的,我们就可以使用Scanner来直接得到值。

import java.util.*;class Main {public static void main(String[] args) {Scanner cin = new Scanner(System.in);n = cin.nextInt();s = cin.nextInt();a = cin.nextInt();b = cin.nextInt();}
}

方式二:使用BufferedReader函数(输入数据量大推荐使用,效率更高)

说明:推荐使用Integer.parseInt来进行转int类型数据。

举例:1015. 摘花生的输入案例

题库输入描述:
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。输入举例:
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5

分析:对于这类不是固定的数据长度,可能会根据T组会有很大很大的读入操作,此时更推荐使用BufferedReader而不是Scanner!

首先用Scanner熟悉下写如下,仅仅只是为了演示:

//Scanner属于java.util包下
import java.util.*;class Main {static final int N = 1010;static int count, m, n;static int arr[][] = new int[N][N];public static void main(String[] args) {Scanner cin = new Scanner(System.in);//int num = cin.nextInt() 可通过'空格'或换行'\n'来作为分割读取一个整型数据//long num = cin.nextLong();//通用方法使用cin.nextLine();读取一行,然后去使用split(" ")来进行分隔成一个数组count = Integer.parseInt(cin.nextLine());while (count != 0) {String[] s = cin.nextLine().split(" ");n = Integer.parseInt(s[0]);m = Integer.parseInt(s[1]);//读取每行每列for (int i = 0; i < n; i++){s = cin.nextLine().split(" ");for (int j = 0; j < m; j++) {arr[i][j] = Integer.parseInt(s[j]);}}//业务处理,针对于int [][]arr//************printAll(n, m);//测试读入的数据//************count--;}}//辅助:额外的public static void printAll (int n, int m) {System.out.printf("n = %d\n", n);System.out.printf("m = %d\n", m);for (int i = 0; i < n; i++){for (int j = 0; j < m; j++) {System.out.printf("%d ", arr[i][j]);}System.out.println();}System.out.printf("*****************\n");}}

接下来使用BufferedReader,BufferedReader实际上与Scanner大差不差,我来写出相应的不同处:

//替换一:Scanner cin = new Scanner(System.in);
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));//替换二:cin.nextLine()
cin.readLine()//替换三:import java.util.*;
import java.io.*;

还有就是在main方法外抛出异常:

throws Exception

其他几乎都是一模一样,下面给出完整代码:

package com.changlu.java;import java.io.*;public class Test {static final int N = 1010;static int count, m, n;static int arr[][] = new int[N][N];public static void main(String[] args)throws Exception {BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));count = Integer.parseInt(cin.readLine());while (count != 0) {String[] s = cin.readLine().split(" ");n = Integer.parseInt(s[0]);m = Integer.parseInt(s[1]);//读取每行每列for (int i = 0; i < n; i++){s = cin.readLine().split(" ");for (int j = 0; j < m; j++) {arr[i][j] = Integer.parseInt(s[j]);}}//业务处理,针对于int [][]arr//************printAll(n, m);//测试读入的数据//************count--;}}//辅助:额外的public static void printAll (int n, int m) {System.out.printf("n = %d\n", n);System.out.printf("m = %d\n", m);for (int i = 0; i < n; i++){for (int j = 0; j < m; j++) {System.out.printf("%d ", arr[i][j]);}System.out.println();}System.out.printf("*****************\n");}}


实战选择案例

BufferedReader适用于所有输入场景。最佳选择如下:

输入数据量很小,一般确定几个值选择使用Scanner,可以直接接收指定类型数据方便。

数据数据量由N决定,不确定长度或者数量特别多,就选择使用BufferedReader。

这里使用acwing的一道题来进行测试:1236. 递增三元组

读题的输入案例:

输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,…AN。
第三行包含 N 个整数 B1,B2,…BN。
第四行包含 N 个整数 C1,C2,…CN。1≤N≤105,
0≤Ai,Bi,Ci≤105

可以看到该题最佳选择输入的函数应该是BufferedReader,因为输入的数据量很大,完全是由N决定,我们来测试一下效果:

①使用Scanner

import java.util.*;class Main {static final int N = 100010;static int n;static int[][] arr = new int[3][N];public static void main(String[] args){//读入数据Scanner cin = new Scanner(System.in);n = cin.nextInt();for (int i = 0; i < 3; i++) {for (int j = 0; j < n; j++) {arr[i][j] = cin.nextInt();}}//排序Arrays.sort(arr[0], 0, n);Arrays.sort(arr[1], 0, n);Arrays.sort(arr[2], 0, n);long ans = 0;int a = 0, c = 0;//以B数组的所有数据作为基准for (int i = 0; i < n; i++) {int target = arr[1][i];while (a < n && arr[0][a] < target) a++;while (c < n && target >= arr[2][c]) c++;//其中n - c一定要添加long来进行转换,否则就会当成int类型来计算ans += (long)(a * (long)(n - c));}System.out.println(ans);}
}

②使用BufferedReader

import java.util.*;
import java.io.*;class Main {static final int N = 100010;static int n;static int[][] arr = new int[3][N];public static void main(String[] args) throws Exception{//读入数据BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));n = Integer.parseInt(cin.readLine());for (int i = 0; i < 3; i++) {String[] s = cin.readLine().split(" ");for (int j = 0; j < n; j++) {arr[i][j] = Integer.parseInt(s[j]);}}//排序Arrays.sort(arr[0], 0, n);Arrays.sort(arr[1], 0, n);Arrays.sort(arr[2], 0, n);long ans = 0;int a = 0, c = 0;//以B数组的所有数据作为基准for (int i = 0; i < n; i++) {int target = arr[1][i];while (a < n && arr[0][a] < target) a++;while (c < n && target >= arr[2][c]) c++;//其中n - c一定要添加long来进行转换,否则就会当成int类型来计算ans += (long)(a * (long)(n - c));}System.out.println(ans);}
}

结论:可以看到仅仅对于输入量特别大的案例,选择一个合适的输入函数可以节省几秒,请务必重视你的输入函数选择!!!

输出

方式一:采用System.out.printf()(输出数据量少可使用)

输出案例:741. 斐波那契数列

输出样例:
Fib(0) = 0
Fib(4) = 3
Fib(2) = 1

有些使用输出不仅仅让我们输出结果,可能会让我们输出相应的结果式子,一般使用的System.out.printf()以及System.out.println()

System.out.printf() //这个printf跟c语言的效果一致,如printf("%d", 123)System.out.println() //使用这个println()就不能写表达式了,输出后会自带一个\n

根据样例来编写代码:

class Main {public static void main(String[] args) {System.out.printf("Fib(%d) = %d\n", 0, 0);//下面两条等价于 => System.out.printf("Fib(%d) = %d\n", 4, 3);System.out.printf("Fib(%d) = %d", 4, 3);System.out.println();System.out.printf("Fib(%d) = %d\n", 2, 1);}
}

方式二:采用PrintWriter(输出数据量大推荐使用)

简单示例

注意:在进行printf等其他输出函数后(可多条),最终一定要执行flush,才能够打印到控制台上。

class Main {public static void main(String[] args) {PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));out.printf("%d\n", 123);out.flush();//刷新流}
}

对应PrintWriter对象的实例方法如下,基本上与方式一的System.out一致:

实战案例场景

这里拿一个acwing题目来进行举例:1265. 数星星

题目中需要让我们输出N个数,这个N的范围为1≤N≤15000,十分大,若是使用System.out.printf来进行输出就会超时:

我们将System.out.printf替换为PrintWriter并且使用println()来进行输出,就能够通过了:

这里给出示例代码,小伙伴们也可以去尝试一下:

import java.util.*;
import java.io.*;class Main {static BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));static final int N = 32010;static int n;//树状数组、索引数组static int[] tr = new int[N], index = new int[N];public static int lowbit(int x) {return x & -x;}//在x位置+1public static void add(int x) {for (int i = x; i < N; i += lowbit(i)) {tr[i]++;}}//计算前缀和public static int sum(int x) {int ret = 0;for (int i = x; i > 0; i -= lowbit(i)) {ret += tr[i];}return ret;}public static void main (String[] args) throws Exception{n = Integer.parseInt(cin.readLine());for (int i = 0; i < n; i++) {String[] s = cin.readLine().split(" ");int x = Integer.parseInt(s[0]);x++;//统计星级的数量(统计出为0的数量)index[sum(x)]++;//再进行加1add(x);}for (int i = 0; i < n; i++) {//上面声明:static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));//效率由高到低比较://[PrintWriter].println() > [PrintWriter].printf() > System.out.println() > System.out.printf()//经过测试:out.println(index[i]); 比 out.printf("%d\n", index[i])效率更高,后者在该题中也会超时。out.println(index[i]);}out.flush();}
}

Java读取文件

实际习题(填空题):蓝桥杯题解 寻找2020 Java答案、第十一届蓝桥杯JavaB组试题B:寻找2020(2020.txt文件)

//填写绝对路径
FileReader fileReader = new FileReader("E:\\自学历程\\Gitee仓库\\demo-exer\\algorithm-java\\src\\main\\resources\\2020.txt");
//传入相应的FileReader即可
BufferedReader cin = new BufferedReader(fileReader);//读取方式,与之前的一致
cin.readLine();

常用集合类

常用api

//数组拷贝(只能拷贝一维,对于多维只能for循环进行拷贝)
int[] arr = {1, 2, 3, 4};
int[] clone = arr.clone();
//数组排序,在区间进行排序[i, j]
Array.sort(clone, i, j + 1);//自定义排序以及区间
Integer arr = new Integer[n];
Arrays.sort(arr, 1, n + 1, (a, b)->{int s1 = s(a);int s2 = s(b);return s1 == s2 ? a - b : s1 - s2;
});//向上取整
Math.floor()
//向下取整
Math.ceil()//多维数组初始化
int[][][] a = new int[1][1][1];//更方便些//转int型
Integer.parseInt("02") //2
//输出一个数字补0
printf("%02d", 1);//01//Pair键值对
Pair<Integer, Integer> pair = new Pair<>(1, 2);
System.out.println(pair.getKey());
System.out.println(pair.getValue());//唯一集合容器
Set<xx> t = new HashSet<xx>();          t.add(xx); [若是添加已经有,返回false]                t.contains(xx)//栈集合
Stack<xx> s  = new Stack<xx>();          s.push(xx);                s.isEmpty()     s.pop()//动态数组集合(可动态扩容的一个数组)
List<Integer> list = new ArrayList<Integer>();    list.size();   list.get(i);//链表集合
new LinkedList<Node>()    getFirst()    addFirst   removeLast()   isEmpty()//双端队列
ArrayDeque<Integer> dq = new ArrayDeque<Integer>(); dq.peekFirst() dq.peekLast()  dq.pollFirst()  dq.pollLast();  dq.getFirst() dq.getLast()  dq.addLast(i)  //队列(链表集合中就有队列的实现)
Deque<TreeNode> queue = new LinkedList<>();   出队:queue.poll()  入队:queue.offer(node.left); 查看第一个:queue.peekFirst()  删除最后一个:queue.removeLast()//哈希表
HashMap<Integer, Integer> map = new HashMap<>();   map.containsKey();//优先队列
PriorityQueue<Integer> queue = new PriorityQueue<>((o1,o2)->o2.compareTo(o1));//集合转数组
String[] strArrayTrue = (String[]) arrayList.toArray(new String[0]);//集合转数组:
ArrayList<Integer> res = new ArrayList<>();int[] ts = (int[])(res.toArray(new int[]));//自定义比较器
compare()返回值:https://blog.csdn.net/weixin_44998686/article/details/109550175
return 0:不交换位置,不排序
return 1:交换位置
return -1:不交换位置
return o1-o2:升序排列
return o2-o1:降序排列//打印long类型
System.out.printf("%s", String.valueOf(1L));

注意排序的话需要使用:

compare()返回值:https://blog.csdn.net/weixin_44998686/article/details/109550175
return 0:不交换位置,不排序
return 1:交换位置
return -1:不交换位置
return o1-o2:升序排列
return o2-o1:降序排列

注意点:对于compareTo返回int,尽量不要使用Integer的属性来调用compareTo,否则很容易出现问题。


Java基本模板

在Java里,方法是从main函数开始运行的,main函数是静态方法,在算法竞赛里我们无需去new当前自己定义的class类名再去调用方法,一般情况都是直接定义static静态函数方法的,在main方法中可以直接进行调用:

模板

import java.util.*;//包含常用的集合工具类如队列、动态数组、哈希表、栈
import java.io.*;//包含BufferedReader、InputStreamReaderclass Main {//输入、输出函数static BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));//定义公共变量一般就是我们需要读入的数据static final int N = 100000;//一般是给定题目的最大数据范围static int count, n, m;static int[][] arr = new int[N][N];public static void main(String[] args) {//读入String line = cin.readLine();String[] s = line.split(" ");//转Int:使用Integer.parseIntint n = Integer.parseInt(s[0]);//输出。一定要注意最后要带上out.flush()out.printf("%d\n", n);out.flush();//调用函数方法func1();func2();}public static void func1() {//功能1}public static void func2() {//功能2}
}

算法竞赛Java选手的语言快速熟悉指南相关推荐

  1. OWL2 Web本体语言快速参考指南

    2019独角兽企业重金招聘Python工程师标准>>> 本文档<OWL2 Web本体语言入门>是W3C发布的OWL 2 Web Ontology Language Pri ...

  2. go语言快速学习指南

    哈喽,大家好,不知道出于什么原因,突然想学习一门"靠谱的语言",随便想想,原因可能有很多, 如: 从事.net 我还能走多远?走多深的技术? 如果未来的某一天.net core升级 ...

  3. 【gRPC】ProtoBuf 语言快速学习指南

    继上篇[gRPC] 在.Net core中使用gRPC了解了gRPC的使用,gRPC基于HTTP/2和ProtoBuf,ProtoBuf就非常有必要好好了解一下了, 那么ProtoBuf究竟是什么? ...

  4. Go 语言快速入门指南:结构体

    Go语言中没有"类"的概念,也不支持"类"的继承等面向对象的概念. Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 1. 类型别名和自 ...

  5. java算法竞赛:StringBuilder更省空间更快速

    参考文章:Java StringBuffer 和 StringBuilder 类      String.StringBuffer与StringBuilder之间区别 用java写代码时,总会一不小心 ...

  6. java算法竞赛:快速读入输出

    我们在使用java写算法题时,常常会因为超时而苦恼,明明是和C++一样的思路,甚至代码实现都极为相似,但是却比它慢上一大截,这时候不妨试试IO流读入输出数据,提升速度. 参考文章 Java写算法题中那 ...

  7. java算法竞赛必备之快读快写(超详细解读)

    java算法竞赛必备之快读快写(超详细解读) java写算法的缺点:速度慢.读写复杂.莫名WA(错误答案).TL(超时).CL(超内存)- (那我们还学个啥啊,都转c++写算法不香嘛.)别急别急,有缺 ...

  8. 学完java学swift_前言最近学完Swift之后一直没有机会实战,发现由于Swift发展历史原因,目前网上大部分的算法都是使用C、Java或其他语言实现的,几乎没有使用Swift实...

    前言 最近学完Swift之后一直没有机会实战,发现由于Swift发展历史原因,目前网上大部分的算法都是使用C.Java或其他语言实现的,几乎没有使用Swift实现的,所以自己打算使用Swift去实现一 ...

  9. c语言二分法查找一个数_算法竞赛小专题系列(1):二分法、三分法

    本系列是这本算法教材的扩展资料:<算法竞赛入门到进阶>. 罗勇军.郭卫斌. 清华大学出版社 二分法和三分法是算法竞赛中常见的算法思路,本文介绍了它们的理论背景.模板代码.典型题目. 1. ...

最新文章

  1. MindInsight训练可视整体设计介绍
  2. java线程挂起唤醒_JAVA并发(10)—interrupt唤醒挂起线程
  3. 阿里云前端周刊 - 第 11 期
  4. LeetCode算法题13:DFS/BFS - 单词搜索
  5. 专精开发还是转管理?程序员的职业规划选择,没有想象中那么难
  6. Error -26612: HTTP Status-Code=500 (Internal Server Error) ...
  7. 数据库-null值和notnull操作
  8. 做技术的,这些观点真的扯淡!
  9. redis aof 备份和恢复_Redis 持久化机制的介绍,了解这些流程很重要
  10. 用ajax下载字节流形式的excel文件
  11. Pcap封包维护工具
  12. [转载] 【Python】set() 集合操作与运算 元素输出顺序
  13. 14c语言合并两个字符串,C语言的标识符和字符数据、字符串数据.ppt
  14. python设置excel格式_Python使用xlwt写excel并设置写入格式
  15. ENVI5.3 辐射校正相关操作
  16. Kubernetes 学习总结(29)—— 使用 kubeadm 部署 Kubernetes 1.24 详细步骤总结
  17. 深度测评 | 五大主流多端开发框架全面对比
  18. 放心吧,社区团购是兔子的尾巴长不了
  19. Python:Numpy—rand、randn
  20. flex横向纵向间距,自适应排列

热门文章

  1. 【满分】【华为OD机试真题2023 JAVAJS】猜字谜
  2. SCI论文如何写--斯坦福大学公开课-Writing in the Sciences
  3. 微博和微信对企业的作用
  4. 自动跟踪太阳光电路设计
  5. ASN.Net 发布后访问报:<customErrors> 标记的“mode”属性设置为“Off”的错误问题的解决方案
  6. 全息投影必须要有全息介质吗?
  7. 2021年申请高新技术企业认定需要满足什么条件
  8. “多个帮主同意某人加入工会”思考异步编程的问题
  9. Saddleback Search
  10. 《神之惩戒——MMORPG的困局》