【语言热身】Java 基础(热身索引)
由于各种原因,我在平时写代码或刷题时,每隔一定时期的就要进行语言切换(C、C++、Python、JavaScript、Java、Go),导致一些常用的语法或写题技巧老是记混,每次卡壳都要去搜一搜。
本文将随着刷题进度持续记录一些使用 Java 语言刷题时必须记住的要素,快速解决在语法方面的障碍。如果你打算开始使用 Java 语言进行刷题时,可以通篇浏览实现快速热身。
本文主要内容:
- 必背写法与重要函数用法
- 集合增删改查与字符串操作速查
- 语言无关的通用技巧
ACM 模式下的输入输出详看:站内文章【语言热身】Java 编写其他输入输出模式
本文题目难度标识:🟩简单,🟨中等,🟥困难。
Java 语法基础
代码风格
看看爪哇代码长啥样先,试图唤起尘封的记忆 😅😅😅
1 | public class Solution{ // 惯例一个文件一个类,文件名与类名相同 |
讨论类的定义和静态上下文的问题:
1 | // 一个文件可以有多个类,但只能有一个与文件名同名的public类 |
操作符
一些注意点:
操作 | 说明 | 备注 |
---|---|---|
右移操作 | 算数右移:>> 逻辑右移: >>> |
记得和别的语言进行区分 |
取模运算 | 由于 Java 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正:int modulus = (sum % k + k) % k; |
相关题目:🟨 974. 和可被 K 整除的子数组 - 力扣(LeetCode) |
优先级 | 恒等运算符优先级比位运算符更大,因此正确写法为:(num&mask)==0x01 |
这是语言之间普遍的优先级 |
值传递
有时候搞不清 Java 到底是引用传递还是值传递,根本原因是「值传递」没有理解透。
Java 中的函数传递本质是值传递的。
函数中如果传递的参数是对象 Object
,那么传递的只是对象的引用。我们可以利用这个引用去修改对象,但如果在函数内重新 new Object()
,函数返回时,主函数不会发生变化。
1 | public class Test { |
1 | class Node { |
此外需要注意的是 Java 在传递参数给方法前,都会计算参数的值。后文聊到 Map
的 getOrDefault
方法时会提到。
数组 Arrays
声明与初始化
1 | // 一维数组 |
排序 Arrays.sort
流 Arrays.stream
Arrays.stream()
可以将数组转换为流,以使用更多的操作。
1 | int[] arr1 = {1, 2, 3, 4, 5}; |
其他
使用 Arrays.equals(array1, array2);
比较两个数组的元素是否相等。
1 | // 比较两个数组是否相等 |
Arrays.copyOf()
方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。Arrays.copyOf()
的第二个参数指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。
1 | int[] arr1 = {1, 2, 3, 4, 5}; |
更多关于
Arrays.copyOf()
的源码解读详见文章:站内文章搞清楚 Java 中 List 的 toArray 方法。
Arrays.fill()
将指定的 int 值分配给指定 int 型数组的每个元素。
1 | int[] arr1 = {1, 2, 3, 4, 5}; |
字符串 String
1 | // 字符串相等判断 |
操作 | String |
StringBuffer /StringBuilder |
---|---|---|
增 | + 操作符。注意从左到右结合性 |
sb.append(str); sb.insert(int offset, str); |
删 | 不可变类 | sb.delete(start, end) sb.deleteCharAt() |
改(替换字符) | replace(char oldChar, char newChar) :返回新的字符串,原字符串不改变。replaceAll(String regex, String replacement) :返回新的字符串,原字符串不改变。replaceFirst(String regex, String replacement) :返回新的字符串,原字符串不改变。 |
sb.replace(start,end, str); :将起始位置为 start,结束位置为 end-1 的子串替换为 str。不生成新的 StringBuilder 对象,在原来的 StringBuilder 对象上修改。sb.setCharAt(index,c) |
查 | str.charAt(index); |
相同 |
长度 | str.length(); |
StringBuilder
还提供以下函数:
sb.reverse()
:反转字符串sb.toString()
:返回字符串sb.capacity()
:返回当前容量。注意,和返回有效长度sb.length()
不一样!
String
子串的获取:
str.substring(int beginIndex)
str.substring(int beginIndex,int endIndex)
。不含endIndex
。
String
大小写转换:
str.toUpperCase()
str.toLowerCase()
String
查字符、字符串第一次出现的位置:
str.indexOf(c)
字符、字符串与数字之间的转换
单步骤转换:
一招静态方法 valueOf
可以解决大部分转换难题。被转的放里面。
Character[]
char[]
互转详见:站内文章【语言热身】Java 中的排序。
我们在处理输入输出字符串题目时的连招:
1 | // 把字符串转换成字符数组处理,更丝滑。不然只能疯狂 s.charAt(i) 咯 |
StringBuffer
和 StringBuilder
中的构造方法和其他方法几乎是完全一样的。StringBuilder
非线程安全,但速度更快。一般情况下(比如刷题)推荐使用 StringBuilder
。
String
保留小数精度的处理可看 站内文章【语言热身】Java 编写其他输入输出模式。
基础函数
1 | // 输出 |
集合 Collection
/Map
调试(标准化输出)
1 | System.out.println(object); // 标准输出 |
Object
的 toString()
默认实现并不直观。
对数组进行「友好」的字符串转换:
1 | Arrays.toString(arr);// 将数组转换为可视字符串 |
ArrayList
、HashSet
继承了 AbstractCollection
,里面重写了 toString
。我们可以这样直观查看 ArrayList
中的内容:
1 | System.out.println(c); |
附 AbstractCollection
中 toString
源码:
1 | public String toString() { |
多线程编程
本章节主要就是背单词!
LeetCode 中的多线程编程题目不多,掌握以下同步模式可解决大部分的问题:
Semaphore
信号量
1 | Semaphore s = new Semaphore(0); |
语言无关的通用技巧
数学常识详看:站内文章【刷题日记】算法题常用数学算法和技巧
1 | // double计算时提高精度 |
有时候有些对输入顺序有要求的,我们可以稍微调整一下顺序。
1 | // 函数参数交换 |
魔数
写题时常见的初始化最大最小值:
- 最大值:
0x3f3f3f3f
。 - 最小值:
0xc0c0c0c0
。
根据不同题目要求,我们还可以将最大值设置为 Integer.MAX_VALUE/2
(防止相加溢出)
0x3f3f3f3f
作为整型的最大值?原因如下:
0x3f3f3f3f
的十进制是1,061,109,567
,是10^9
级别的,而一般场合下的数据都是小于10^9
的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。而平时用的Integer.MAX_VALUE=0x7fffffff
不能满足“无穷大加一个有穷的数依然是无穷大”这个条件,加上一个数后,根据补码规范它会变成了一个很小的负数。0x3f3f3f3f
的 2 倍还是一个「无穷大」的数。0x3f3f3f3f
的每 8 位(每个字节)都是相同的。我们在程序设计中经常需要使用memset(a, val, sizeof(a))
初始化一个数组a
,该语句把数值val
(0x00
~0xFF
)填充到数组a
的每个字节上,所以用memset
只能赋值出“每 8 位都相同”的int
。当需要把一个数组中的数值初始化成正无穷时,为了避免加法算术上溢出或者繁琐的判断,我们经常用memset(a, 0x3f, sizeof(a))
给数组赋0x3f3f3f3f
的值来代替。
次方级别的大质数:1000000007
。在一些题目中会很有用:🟥 Problem - 1632D - Codeforces。对于多数题目来说,这个数常用于将结果取余。
模板写法
单调栈/队列
原型题: 🟩 496. 下一个更大元素 I - 力扣(LeetCode)
1 | // 假设数组A从左到右遍历 |
有时候,单调栈或单调队列中不一定存的是实际数字的值,有可能存的是指向实际数字的指针或下标。比如这一题:🟥 239. 滑动窗口最大值 - 力扣(LeetCode)
滑动窗口
样例题:🟨 3. 无重复字符的最长子串 - 力扣(LeetCode)
1 | public int lengthOfLongestSubstring(String s) { |
方向移动
如果需要物体在规定的棋盘下(比如 n*n
)进行方向移动,可以这样写:
1 | // 定义方向 |
相关题目:🟨 688. 骑士在棋盘上的概率 - 力扣(LeetCode)
本文参考
- 我久远积灰的笔记
- 牛客网在线编程_算法笔试_输入输出练习 (nowcoder.com)
- java中String和StringBuilder的replace方法-CSDN博客
- Java-修改 String 指定位置的字符最全方法总结(StringBuilder 和 StringBuffer 的使用以及区别)_string替换指定位置字符-CSDN博客
- Java保留两位小数的几种写法总结[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com)
- Java:获取子字符串 substring()_java substring(10)-CSDN博客
- java.util.TreeSet.floor()方法和java.util.TreeSet.ceiling()方法_treeset的ceil和floor-CSDN博客
- 大质数表 - ljxtt - 博客园
- 0x3f3f3f3f是什么意思???-CSDN博客
- Java中的Set remove()方法及其示例|极客笔记
- Java中List,Set,数组的互相转换_java 1.8 list转set-CSDN博客