Java 刷算法时的常用 API 以及一些奇技淫巧,当时参加蓝桥杯总结的,隔一段时间再刷题的时候总会拿出来看看
Java 语法操作
输入 输出
对字符串的获取可以采用 next()
和 nextline()
,用 hasNext()
或 hasNextline()
判断是否还有数据输入
hasNext()
或 hasNextline()
在 while 循环中可能没啥区别,但 next()
和 nextline()
却大有不同
next()
不能读取空格,换言之,读取到有效字符之后遇到空格就会停止,但 nextline()
以 Enter 结束,能存储对应格式的任何字符
多行输入
存在输入多行,且每行输入的字符或数字个数不定的情况,这就需要将 hasnext()
和 nextline()
搭配使用
具体方法是实例化两个 Scanner
对象 former 和 latter,其中 latter 的参数是 former 的 nextline()
,然后使用 hasnext()
判断获取到的行是否存在下一个输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Scanner scanner = new Scanner (System.in);int N = scanner.nextInt();scanner.nextLine(); int [] arr = new int [10000 ];int count = 0 ;for (int i = 0 ; i < N; i++) { Scanner input = new Scanner (scanner.nextLine()); while (input.hasNext()) { arr[count++] = input.nextInt(); } }
输入字符
Java 中不提供 nextChar()
的方法,但可以使用next().charAt(0)
1 2 3 4 5 6 7 8 9 10 Scanner sc = new Scanner(System.in); char c= sc.next().charAt(0); // 将不空格的一串字符按数组存储:`sc.next().toCharArray();` int n = sc.nextInt(); int m = sc.nextInt(); char[][] arr = new char[n][m]; for (int i = 0; i < n; i++) { arr[i] = sc.next().toCharArray();// 读入字符串拆分成字符数组 }
格式化输出
String.format()
和 System.out.printf()
可以进行格式化的输出效果
%4d
和 %-4d
的区别: %4d
是靠右输出四位,不足用空格补齐; %-4d
是靠左输出
输出 N 位小数,可以使用 DecimalFormat
对格式进行定义;或者使用 String.format(格式, 浮点变量)
直接打印
1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) { float f= (float ) 3.234567 ; System.out.println(f); DecimalFormat df=new DecimalFormat ("#0.00" ); System.out.println(df.format(f)); System.out.printf("%.2f\n" ,f); System.out.println(String.format("%.2f" ,f)); }
结果:2.35 2.35
循环的注意
判断引用型
引用型在循环中的判断不能直接使用 ==
, 因为即便内容相等的两个数也有可能被引用的地址不相同,而 ==
比较的就是引用的地址如下面这种情况:
1 2 3 String str1 = "hello" ;String str2 = "HELLO" .toLowerCase();
对引用型的数据统一使用 equals()
的方式进行判断: if(s1.equals(s2)){···}
但注意如果 s1
的值是空的时候也会报错
所以可以使用 if(s1!=null && s1.equals(s2)){···}
进行判断
switch 的用法
Java 中的 switch 循环支持字符串的匹配,但不要忘记每个语句后面加 break;
Java12 之后的 switch 语句中支持使用 ->
符号取代 :
进行自动跳出的 case 语句,如果一个 case 中要运行多个语句可以用 {}
括起来
数组的操作
初始化数组可以使用 Arrays.fill()
方法
1 2 boolean [] arrPrimer = new boolean [10000 ];Arrays.fill(arrPrimer, Boolean.TRUE);
遍历数组
数组的遍历有三种方式: for()
循环搭配索引、 for each
迭代每个元素(但无法获取索引)、转换成字符串输出
Java 标准库提供的 Arrays.toString()
方法进行将整个数组转换为字符串直接打印输出,二维数组使用: Arrays.deepToString()
1 2 int [] arr={1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 };System.out.println(Arrays.toString(arr));
结果:[1, 2, 3, 4, 5, 6, 7]
数组排序
使用 Arrays 中的 sort 方法可以对数组进行快速排序;若要实现降序排序可以使用 Collections.reverseOrder()
方法(仅对类起作用)
1 2 3 4 5 6 7 int [] arr = {1 , 3 , 6 , 2 , 4 , 8 , 7 , 9 };Arrays.sort(arr); Integer[] arr = {1 , 3 , 6 , 2 , 4 , 8 , 7 , 9 }; Arrays.sort(arr, Collections.reverseOrder()); for (int m : arr) System.out.print(m + " " );
拷贝数组
可以直接使用数组自身的 .clone()
方法,因为数组是引用型,将数组放入方法或者类中很容易导致内外部操作互相影响,所以 .clone()
方法在这种场景下常用
1 2 3 4 5 int [] arr = {1 , 4 , 5 , 2 , 8 , 12 , 99 , 345 , 234 , 6 };int [] copy = arr.clone();System.out.println(Arrays.toString(arr)); System.out.println(Arrays.toString(copy));
系统提供的数组拷贝方法: System.arraycopy(Object a, int begin_a, Object b, int begin_b, int length);
1 2 3 4 5 6 7 public static void main (String[] args) { int a[]={1 ,2 ,3 ,4 }; int b[]=new int [10 ]; System.arraycopy(a,0 ,b,0 ,3 ); for (int n:b) System.out.print(n+" " ); }
结果:1 2 3 0 0 0 0 0 0 0
将一个数组的一部分拷贝到另一数组中可以使用 Arrays.copyOf(object, length);
方法
1 2 3 4 5 6 public static void main (String[] args) { int a[]={1 ,2 ,3 ,4 }; int b[]= Arrays.copyOf(a,3 ); for (int n:b) System.out.print(n+" " ); }
结果:1 2 3
Arrays 类
Arrays 类提供很多使用的方法,常见的如下:
1 2 3 4 5 6 7 8 9 10 11 Arrays.asList(Object[] a) public static int binarySearch (Object[] a, Object key) public static boolean equals (Object[] a, Object[] a2) public static void fill (Object[] a, Object val) public static void fill (Object[] a, int fromIndex, int toIndex, Object val) public static void sort (Object[] a) public static void sort (Object[] a, int fromIndex, int toIndex) public static <T> void sort (T[] a, Comparator<? super T> c)
字符串
Character 类
主要应用其中的字符类型判断函数,可以节约时间
函数名
用途
Character.isDigit(char c)
判断字符 c 是否是数字字符
Character.isLowerCase(char c)
判断 c 是否是小写字母字符
Character.isUpperCase(char c)
判断 c 是否是大写字母字符
Character.isLetterOrDigit(char c)
判断 c 是否是字母或数字字符
String 类
存入两个字符相同的 string 型时,两者的地址也相同(将后创建的地址指向前者,节约内存);但是 new String 的两个不同对象的内容即便相同地址也不同
1 2 3 4 5 6 7 8 9 10 public static void main (String[] args) { String a="asd" ; String b="asd" ; boolean t=a==b; String c=new String ("iop" ); String d=new String ("iop" ); boolean y=c==d; System.out.println(t); System.out.println(y); }
结果:
true
false
判断 string 对象是否相同用自带的 .equals()
方法,同时还提供一种忽略大小写的判断方法 .equalsIgnoreCase()
1 2 3 4 5 6 7 8 9 10 public static void main (String[] args) { String a = "asd" ; String b = "asd" ; if (a.equals(b)) { System.out.println("==" ); } else { System.out.println("!=" ); } System.out.println(a.equalsIgnoreCase(b.toUpperCase())); }
结果:==
true
要想遍历 string 的字符内容,需要将其转换为字符数组
1 2 3 4 5 6 public static void main (String[] args) { String a = "asd" ; char arr[] = a.toCharArray(); for (char n : arr) System.out.print(n + " " ); }
结果:a s d
方法
目的
contains()
是否包含相应的字符或子串
trim()
移除首位空白字符(\t, \r, \n)
isEmpty()
是否为空
isBlank()
是否为空白字符串
replace()
替换字符(串)
join("?",arr)
用指定字符连接字符或字符串
split("?")
分割字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void main (String[] args) { String s = "asdeGHAasDeFg" ; for (int i = 0 ; i < s.length(); i++) { char c = s.charAt(i); } s.indexOf('s' ); s.indexOf('s' , 2 ); s.lastIndexOf('s' ); s.lastIndexOf('s' , 6 ); String[] ss = s.split("s" ); String str1 = s.substring(2 , 5 ); char [] cs = s.toCharArray(); String str2 = s.toLowerCase(); String sToL = s.toUpperCase(); String sToU = String.valueOf(123 ); }
StringBuilder
StringBuilder 对象被当作是一个包含字符序列的变长数组,在需要频繁更改字符串的场景下常用
1 2 3 4 5 6 7 8 9 public static void main (String[] args) { var sb = new StringBuilder ("String" ); sb.append("123" ); sb.append("456" ).append("789" ); sb.reverse(); sb.delete(3 , 7 ); sb.deleteCharAt(3 ); sb.insert(4 , "string" ); }
StringJoiner
在 String 中有 join
方法进行使用特定字符连接字符串,但如果数据太多就不实用了
1 2 3 4 5 6 7 8 9 public static void main (String[] args) { var sj = new StringJoiner (" +++ " , "Hello: " , "!" ); String[] strArr = {"Aidan" , "Amy" , "Bob" , "Jack" , "Jhon" }; for (String each : strArr) { sj.add(each); } System.out.println(sj); }
结果:Hello: Aidan +++ Amy +++ Bob +++ Jack +++ Jhon!
边界处理
数组判空: if(arr == null|| arr.length == 0)
二维数组判空: if(arr == null || arr.length == 0 || arr[0].length == 0)
字符串判空: if(str == null || str.equals(""))
所有封装类的最大最小值都有其存在的方法: Integer n=Integer. MAX_VALUE;
浮点数的判断条件,因为浮点数的值往往没法准确进行显示,所以对数据较为精确的题目的判断条件要使用差的绝对值小于某个临界值的形式: Math.abs(x-0.1)<0.00001
有些数据的处理还要使用扩大 1000(甚至更大)倍转换成 Long Long
形式,然后在输出的时候除以之前扩大的倍数
格式转换
程序运算时会进行自动转型,但这是由下向上转型,所有有些时候需要进行强制转型
最简单直接的是在变量前加(目标类型),此方法只用于基本的数据类型,不支持 String 类型
String 和其他基本数据类型的转换
可以使用 toString
将其他数据类型转换为 String 类,但这种方法只对包装类起作用(如:Integer)
使用 String 自带的 valueOf()方法,支持将基本的数据类型转换
而将 String 转换为其他,可以用自带类的.parseXXX(string)方法
1 2 3 4 5 Integer a=new Integer (100 ); String s1=a.toString(); int i=99 ;String s2=String.valueOf(i); Integer b=Integer.parseInt(s2);
快速排序
实用 Arrays 中的 sort 方法可以对数组进行快速排序
若要实现降序排序可以使用 Collections.reverseOrder()
方法(数组必须为 Integer 类)
1 2 3 Integer[] arr = {1 , 4 , 5 , 2 , 8 , 12 , 99 , 345 , 234 , 6 }; Arrays.sort(arr); Arrays.sort(arr, Collections.reverseOrder());
比较器
使用 Comparator 类定义的比较器可以实现自定义排序
排序自定义类 (结构体) 时也可以使用 comparable 接口在类中直接覆写方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import java.util. Arrays; public class Test { public static void main (String[] args) { Person[] arr = new Person []{new Person (12 , "Aidan" ), new Person (6 , "John" ), new Person (12 , "Bob" ), new Person (17 , "Amy" ), new Person (15 , "Dave" ),}; Arrays.sort(arr, (o1, o2) -> { if (o1.age != o2.age) { return o1.age - o2.age; } else { return o1.name.compareTo(o2.name); } }); for (Person each : arr) { System.out.println(each.toString()); } } } class Person { public int age; public String name; public Person (int age, String name) { this .age = age; this .name = name; } @Override public String toString () { return " 姓名:" + name + ",年龄:" + age; } }
大数类
大数类分为整型 BigInteger
和浮点型BigDecimal
定义 BigInteger 类型可以使用实例化类的方法,也可以使用 BigInteger 中的 valueOf(数字 / 变量)
1 2 3 4 BigInteger a = new BigInteger ("3" );BigInteger b = BigInteger.valueOf(3 );int i = 788 ;BigInteger c = BigInteger.valueOf(i);
大数的类是在 java.math.* 包里的,所以继承了 math 的所有方法,而运算也是使用方法来进行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 BigInteger a = new BigInteger ("3" );BigInteger b = BigInteger.valueOf(-3 );int i = 788 ;BigInteger c = BigInteger.valueOf(i);BigInteger ad=a.add(c); BigInteger sub=a.subtract(b); BigInteger mul=a.multiply(b); BigInteger div=c.divide(a); BigInteger re=c.remainder(a); BigInteger ab=b.abs(); System.out.println(ad); System.out.println(sub); System.out.println(mul); System.out.println(div); System.out.println(re); System.out.println(ab);
结果:791 6 -9 262 2 3
BigDecimal 使用 .scale()
表示小数位数
具体计算方法与整型差不读,但浮点型进行除法的时候可能会存在除不尽的情况,这样就可以对其进行精度上的取余
判断相等时可能小数位后面存在多个 0 这样虽然不影响大小但在操作的时候会导致大小不同,可以使用 compareTo()
方法
Math 类
可以求 sqrt(平方根)、abs(绝对值)、max、min、pow(幂)、取整 (ceil、floor、round) 具体查阅 API
输出一个随机数用 random()方法
1 2 3 4 5 6 7 8 9 10 public static void main (String[] args) { double c = Math.random(); System.out.println(c); int b = 100 ; int d = (int ) (Math.random() * b + 1 ); System.out.println(d); int a = 50 ; int e = (int ) (Math.random() * (b - a + 1 ) + a); System.out.println(e); }
模板
公约公倍数
求最大公约数可以采用辗转相除法,就是两数的最大公约数就是较小数和两数余数的最大公约数
最小公倍数等于两数的乘积除最大公约数
BigInteger 提供 .gcd(x, y)
方法自动判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Test { static int gcd (int a,int b) { return b==0 ?a:gcd(b,a%b); } static int lcm (int a,int b) { return a*b/gcd(a,b); } public static void main (String[] args) { System.out.println(gcd(12 ,5 )); System.out.println(lcm(12 ,5 )); BigInteger y = BigInteger.valueOf(123 ); BigInteger x = BigInteger.valueOf(12345 ); System.out.println(x.gcd(y)); } }
判断闰年
1 2 3 4 5 6 7 8 public static void main (String[] args) { Scanner sc = new Scanner (System.in); int n = sc.nextInt(); if (n % 400 == 0 || (n % 4 == 0 && n % 100 != 0 )) System.out.println("true" ); else System.out.println("false" ); }
判断质数
质数的判断一般有三种方式:定义方法、遍历因子、打表
一二种的理念相同:遍历因子看能否取余,因子最大不会超过 X 的 sqrt
打表的复杂度最低
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static boolean judge (int x) { boolean flag = true ; for (int i = 2 ; i <= Math.sqrt(x); i++) { if (x % i == 0 ) { flag = false ; break ; } } return flag; } while (count < N) { boolean flag = true ; for (int j = 2 ; j * j <= i; j++) { if (i % j == 0 ) { flag = false ; break ; } } } boolean [] arrPrimer = new boolean [10000 ];Arrays.fill(arrPrimer, Boolean.TRUE); for (int i = 2 ; i * i < 10000 ; i++) { for (int j = 2 ; j * j < 10000 ; j++) { arrPrimer[i * j] = false ; } }
进制转换
在 Integer 对象中,常用的进制转换
十进制的转换对象
对应的方法和参数
返回值
数字转换字符串
Integer.toBinaryString(n);
二进制字符串
数字转换字符串
Integer.toOctalString(n);
八进制字符串
数字转换字符串
Integer.toHexString(n);
十六进制字符串
数字转换字符串
Integer.toString(n, r);
r 进制字符串
字符串转换数字
Integer.parseInt(str, r);
r 进制整数
1 2 3 4 5 6 7 8 9 10 11 public static void main (String[] args) { int n=18 ; System.out.println(Integer.toBinaryString(n)); System.out.println(Integer.toOctalString(n)); System.out.println(Integer.toHexString(n)); System.out.println(Integer.toString(n,2 )); String s = "10101" ; System.out.println(Integer.parseInt(s,2 )); System.out.println(Integer.bitCount(21 )); }
全排列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static int arr[] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };static int ans = 0 ;static void dfs (int k) { if (k >= 9 ) { ans++; } for (int i = k; i < 9 ; i++) { int t = arr[k]; arr[k] = arr[i]; arr[i] = t; dfs(k + 1 ); t = arr[k]; arr[k] = arr[i]; arr[i] = t; } } public static void main (String[] args) { dfs(0 ); System.out.println(ans); }
走迷宫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import java.util. Scanner; public class MazeDfs { static String path = "" ; static String shortestPath = "" ; public static void main (String[] args) { Scanner sc = new Scanner (System.in); int x = sc.nextInt(); int y = sc.nextInt(); int count = 0 ; int [][] map = new int [x][y]; for (int i = 0 ; i < x; i++) for (int j = 0 ; j < y; j++) map[i][j] = sc.nextInt(); dfs(0 , 0 , map); if (shortestPath.length() != 0 ) System.out.println(" 最短路线为:" + shortestPath); else System.out.println(" 没有找到路线!" ); char [] s = shortestPath.toCharArray(); for (char c : s) { if (c == '-' ) count++; } System.out.println(count); } public static void dfs (int x, int y, int [][] map) { int m = map.length; int n = map[0 ].length; if (x < 0 || y < 0 ) return ; if (x > m - 1 || y > n - 1 ) return ; if (map[x][y] == 1 ) return ; if (x == m - 1 && y == n - 1 ) { path = path + "(" + x + "," + y + ")" ; if (shortestPath.length() == 0 || shortestPath.length() > path.length()) shortestPath = path; System.out.println(" 找到路线:" + path); return ; } String temp = path; path = path + "(" + x + "," + y + ")" + "-" ; map[x][y] = 1 ; dfs(x + 1 , y, map); dfs(x, y + 1 , map); dfs(x, y - 1 , map); dfs(x - 1 , y, map); map[x][y] = 0 ; path = temp; } }
背包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.Scanner;public class BackPack { public static void main (String[] args) { Scanner sc = new Scanner (System.in); int N = sc.nextInt(); int V = sc.nextInt(); int [] v = new int [N]; int [] w = new int [N]; for (int i = 0 ; i < N; i++) { v[i] = sc.nextInt(); w[i] = sc.nextInt(); } int [] dp = new int [V + 1 ]; for (int i = 1 ; i <= N; i++) { for (int j = V; j >= 0 ; j--) { if (j >= v[i - 1 ]) { dp[j] = Math.max(dp[j], dp[j - v[i - 1 ]] + w[i - 1 ]); } } } for (int i = 1 ; i < V + 1 ; i++) { System.out.println(dp[i]); } } }