java常用的Util类&&做题时遇到的一些问题
Util类
一、Sort
1.排序0~n-1,第n个元素不参与排序。
2.如果要排类数组的话,要重写比较器,再加上cmp参数。
3.默认升序,如果要逆序,就必须用Integer数组,不能用int。
Arrays.sort(a, 0, n, cmp);
Arrays.sort(a, 1, q+1, Collections.reverseOrder()); //逆序排下标1~q
二、Class
1.相当于结构体,可以放在public class Main里
2.如果要排序,则需重写比较器
static class hh
{
int v, id;
public hh(int v, int id)
{
this.v = v;
this.id = id;
}
}
static Comparator<hh> cmp = new Comparator<hh>()
{
public int compare(hh o1, hh o2)
{
return o1.v - o2.v; //按v的升序排序
//return o2.v - o1.v; //按v的降序排序
};
};
三(1)、List
1.实现方式:
List<Integer> list = new LinkedList<Integer>();
2.下标从0开始
3.不能自动排序,元素可以重复
4.方法有:add get remove size
5.元素类型只能是对象,如Integer,而不能用int。
6.删除一个元素后,后面元素的下标都会往前移动。
7.输出用for-each方式
for (String s: list) {
System.out.println(str);
}
三(2)、ArrayList
1.实现方式和排序方法:
ArrayList<Integer> res = new ArrayList<>();
Collections.sort(res); //升序
Collections.sort(res, (a, b)->b - a); //降序
sum.sort((o1,o2)->{ //适用于类数组排序
if (o1.s != o2.s) return o1.s - o2.s;
if (o1.c != o2.c) return o1.c - o2.c;
return o1.d - o2.d;
});
四、Set
1.两种实现方式:
TreeSet<Integer> set1 = new TreeSet<Integer>();
HashSet<Integer> set2 = new HashSet<Integer>();
HashSet是哈希表实现的,数据无序
TreeSet是二叉树实现的,数据自动从小到大排好序
2.Set中的数据都是唯一的
3.输出用for-each方式
for(int x : set1)
{
System.out.println(x+" ");
}
五、映射(Map)
1.两种实现方式:
TreeMap<String, Integer> map1 = new TreeMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
HashMap:数组方式存储key/value,key不可以重复,value允许重复 (没有自动排序)
TreeMap:基于红黑二叉树的NavigableMap的实现,key不可以重复,value允许重复,会按照排序后的顺序迭代元素,主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出。(自动按照key进行排序,从小到大。如果key是String,则会像 1616 4615 54 61651 8 这样排)
2.put 放入键值对
map1.put(key, value);
3.get 通过键来获取对应的值
4.利用keyset 集合遍历map
Set<String> key = map1.keySet();
for(String k : key)
{
System.out.println(k + ":" + map1.get(k));
}
六、队列(queue)、优先队列(PriorityQueue)
1.两种实现方式
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
Queue<Integer> q = new LinkedList<Integer>();
队列先进先出,优先队列会对元素进行自动排序。
2.方法
size()返回队列中的元素个数
peek()返回队首元素
poll()移除队列首元素,同时返回首元素的值
3.输出
while(!q.isEmpty())
{
System.out.println(q.poll()+" ");
}
七、栈(Stack)
1.实现方式
Stack<Integer> s = new Stack<Integer>();
后进先出
2.方法
size()元素个数
push()放入元素
peek()输出栈顶元素
pop()弹出栈顶元素,也就是返回栈顶元素的值,并删除。相当于队列的poll()
get(3)输出下标为3的元素,下标从0开始。(先后放进去1 2 3 4 5,会输出4,但栈顶是从5开始)
八、StringBuffer
(1)定义:
StringBuffer sBuffer = new StringBuffer();
StringBuffer sBuffer = new StringBuffer("acwing");
(2)方法:
sb.append(String s)
将指定的字符串追加到ab字符序列。
sb.deleteCharAt(idx);
将idx位置的字符删除。
以上两种方法经常用于字符串DFS
ab.reverse()
将此字符序列用其反转形式取代。
对字符串逆序输出时可以采用ab.reverse().toString()
char charAt(int index)
返回此序列中指定索引处的 char 值。
String toString()
返回此序列中数据的字符串表示形式。
大数类BigInteger
BigInteger可以表示任意大小的整数
定义BigInteger类型可以使用实例化类的方法,也可以使用BigInteger中的valueOf(数字/变量)
BigInteger a = new BigInteger("3");
BigInteger b = BigInteger.valueOf(3);
int i = 788;
BigInteger c = BigInteger.valueOf(i);
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);//除
Math类
Math.max(a,b);//求两个数的较大值
Math.min(a,b);//求两个数的较小值
Math.sqrt(a);//开根
Math.pow(a,b);//求a的b次方的值(幂)
Math.abs(a);//求绝对值
Math.round(a);//四舍五入
Math.ceil(a);//向上取整
Math.floor(a);//向下取整
日期问题
1、将一个八位数数字日期( i = 20011224)的年月日取出来
year = i / 10000;
month = i % 10000 / 100;
day = i % 100;
ps: / 看成取前面的位数
% 看成取后面的位数
2、判断日期是否合法
public static boolean isDate(int y,int m,int d) {
int days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
days[2] = 29;// 闰年二月有29天
} else {
days[2] = 28;// 平年二月有28天
}
// 首先月份只有1到12月
if (m > 0 && m < 13) {
if (d <= days[m] && d > 0) { // 天数从0到该月的最大天数
return true; // 如果合法,返回true
}
}
return false;
}
3、判断回文日期
public static boolean isHuiwen(int i) {
String s = String.valueOf(i);
for(int j = 0;j < s.length() / 2;j++)
if(s.charAt(j) != s.charAt(s.length() - j - 1)) {
return false;
}
return true;
}
//补充:
这里有一个小技巧,就是在枚举日期是否是回文时期时只需要枚举前四位,然后再把前四位翻转拼接到后面再判断日期是否合法
for (int i = 0; i < 10000; i++) {
int x = i;
int r = i;
for (int j = 0; j < 4; j++) {
r = r * 10 + x % 10;
x /= 10;
}
}
4、判断ABABBABA类型回文日期
public static boolean isABHuiwen(int i) {
String s = String.valueOf(i);
char[] arr = s.toCharArray();
char a = arr[0], b = arr[1], c = arr[2], d = arr[3], e = arr[4], f = arr[5], g = arr[6], h = arr[7];
if (a == c && c == f && f == h && b == d && d == e && e == g)
return true;
return false;
}
5、已知今天是星期几,求多少天后是星期几
//可以使用Excel或者计算器直接算
//(w+n)%7
//w:当前日期是星期几
//n:多少天之后
int res;//目标天数是星期几
res= (w + n) % 7;
if(res == 0 )
res = 7;
System.out.println(res);
6、判断一个日期中包不包含某些数字
方法一:
public static boolean check(int n) {
int x;
while(n != 0) {
x = n % 10;
if(x == 2 || x == 4)
return false;
n /= 10;
}
return true;
}
方法二:
public static boolean check(int n) {
String s = String.valueOf(n);
for(int i = 0;i < s.length();i++)
if(s.charAt(i) == '4' || s.charAt(i) == '2')
return false;
return true;
}
7、格式化输出日期
//%02d 不足两位 前面补0
System.out.printf("%d-%02d-%02d\n", year, month, day);
时间问题
1、已知毫秒数,格式化输出时间
long n = Long.parseLong(in.readLine());
//将毫秒转换成秒 1秒= 1000毫秒
n /= 1000;
long h = n / 60 / 60 % 24;
long m = n / 60 % 60;
long s = n % 60;
//%02d 不足两位前面补0
System.out.printf("%02d:%02d:%02d",h,m,s);
2、做时间相关问题的计算
处理时间通常先将时间转化为秒数
int get_seconds(int h, int m, int s){
return h * 3600 + m * 60 + s;
}
将秒数逐一计算出小时数,分钟数,秒数的方式
int hour = time / (60 * 60);
int minute = time % (60 * 60) / 60;
int second = time % 60;
进制转换
//利用BigInteger类实现
//num:要转换的数 from:原进制 to:目标进制
String s = new BigInteger("num",from).toString(to); System.out.println(s);
//也可以用每个对象(这里以Integer为例)对应的方法来实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FUu86p4X-1681176163059)(assets/image-20230401143225246-1680330747710-1.png)]
位运算
1、^(亦或运算)
针对二进制,相同的为0,不同的为1
2、&(与运算)
针对二进制,只要有一个0,就为0
3、>>(右位移运算)
一般把a/2 写做 a>>1
即 a / 2 等价于 a >> 1
4、<<(左位移运算)
一般把a*2 写做 a<<1
即 a*2 等价于 a << 1
2^(d-1) 即 1 << d - 1
注意:+、-运算符的优先级高于<< >>位移运算符
x >> k && 1返回x右起第k位二进制数
一些要注意的问题
1、判断单个字符用“==”而不是equal
if('1' == x[0].charAt(1))
2、int、long的范围
//如何记忆每个数据类型的范围?
//2^(单个数据类型所占的位数 - 1 ) -1
//如 int:2^(4 * 8 - 1) - 1
//一个int占4字节,1字节8个位
int 2*10^9(2^31 -1)
long 9*10^19 (2^64 -1)
3、数组能开的最大范围
//看具体题目说是128MB 还是256MB
//建议不要开太大,不过一般多开10个 如1<=N<=10000,我们开成a[10010]
//因为比如字符串末尾带一个'\0',可以避免很多边界问题
//至于下面所说的这个可以自己去实验一下,在编译器上是没问题的,但是在蓝桥云课测试就是会爆段错误
int[] n = new int[N]; //N 最大是10000000 (10^7),不然编译错误
int[][] n = new int[N][N]; //N 最大是1000 (10^3),不然内存超限
4、double不能直接用 == 比大小
若两者之差小于某个非常小的数,则相等。
Math.abs(x - y) < 1e-8;
5、科学计数法
java中好像只有double类型可以用1e5这类表示形式,记得强转一下
int n = (int)1e6;
6、字符数组下标从1开始输入方式
方式1:
常用空格把a[0]位置占掉
在读入字符时,先读串再转为字符数组。
读串:sc.next()-->char a[]
转换为字符数组a:a[]下标从0开始
如果题目要求a[]下标从1开始,我们需要在输入时用" "占掉一个a[0]的位置
这样a的下标便从1开始
方式2:这个一般在处理前缀和问题的时候会用到
快读快写:
String s[]=bf.readLine.split(" ");
a[]=Integer.parseInt(s[i-1]);
8、常用ASCII值
A - Z 是 65~ 92
a - z 是 97~ 122
0 - 9 是 48~ 57
9、要注意的一些数学问题
除数不能为0 即分母不能为0
可以将/写成*的形式(即除以一个数等于乘上它的倒数)
做/运算的时候要考虑是否需要小数点后的数据(即是否需要double)
做sqrt()开根的时候一定要在前面加(int)强转 最后再判断开出来的数相乘等不等于之前的数