java算法题刷题常用工具
Comparator
1.简介
顾名思义,这是一个比较器,用这个比较器可以自定义比较规则。自定义一个比较器的第一步是要实现java.util.Comparator接口,同时实现其中的int compare(Object o1, Object o2)
方法:
public class CustomizedComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
2.关键方法:int compare()
这个方法就是实现自定义比较规则的地方。先来看下源码中它的定义:
可以看到,如果返回负数表示o1 < o2,返回0表示o1 = o2,返回正数表示o1 > o2。换种说法:如果我们在o1<o2的时候返回一个负数,那就是升序排列。
下面我定义一个int[]数组的欧式距离比较器,比较其距离原点(0,0)的距离:
public class CustomizedComparator implements Comparator<int[]> {
@Override
public int compare(int[] o1, int[] o2) {
int euDistance1 = 0, euDistance2 = 0;
// 欧氏距离计算. 因为不影响结果,所以只取平方和,不进行开根号操作了。
for (int i = 0; i < o1.length; i++) {
euDistance1 += o1[i] * o1[i];
}
for (int i = 0; i < o2.length; i++) {
euDistance2 += o2[i] * o2[i];
}
if (euDistance1 < euDistance2) {
return -1;
} else if (euDistance1 > euDistance2) {
return 1;
} else {
return 0;
}
// return euDistance1 - euDistance2;
}
}
3.常见使用场景
既然叫做比较器,那什么地方需要比较,什么地方就可能用得上Comparator。刷题的时候,最常见的就是排序了。使用到comparator的地方主要有两个:
Arrays.sort(T[],Comparator<? super T> c);
Collections.sort(List<T> list,Comparator<? super T> c);
结合上面的欧氏距离比较器,如果有一些以二维数组表示的点,按照其距离原点的欧氏距离排序:
public void test() {
int[][] points = {{1,2},{0,1},{2,3},{0,0}};
Arrays.sort(points, new CustomizedComparator());// 排序后points = {{0,0},{0,1},{1,2},{2,3}}
// 默认是升序的,如果要降序排列,改变int compare(Object o1, Object o2)方法实现即可
}
PriorityQueue
1.简介
顾名思义,这是一个队列。PriorityQueue——“优先级队列”,除了具有队列“先进先出”的典型特点之外,还常常和上面所讲的Comparator(或是java的Comparable接口)一起,实现排序功能:自动将进入PriorityQueue的元素进行有序排列(或者说插入新元素时,自动插入到合适的位置保证队列有序)。
2.常见使用场景
结合上面对PriorityQueue特点的介绍,很容易想到它的用武之地:求最大n个元素或者最小n个元素的问题。结合上面的CustomizedComparator来举例:
public void test() {
int[][] points = {{1,2},{0,1},{2,3},{0,0}};
PriorityQueue<int[]> queue = new PriorityQueue<>(new CustomizedComparator());
for (int i = 0; i < points.length; i++) {
// 有序插入
queue.add(points[i]);
}
// 输出距离原点最近的前k个点
int k = 2;
for (int i = 0; i < k; i++) {
int[] point = queue.poll(); // 依次输出:{0,0} {0,1}
}
}
3.常用方法
PriorityQueue的常用方法和普通队列Queue是类似的,下面几个是刷题时的常用方法:
boolean add(E e)
:添加一个元素e
boolean offer(E e)
:添加一个元素e(和Queue不同,PriorityQueue中的add和offer完全一样)
E peek()
:获取队首元素(没有弹出)
E element()
:功能和peek()一样,区别在于方法失败时element()抛异常,peek()返回null
E poll()
:弹出队首元素
E remove()
:功能和poll()一样,区别在于方法失败时remove()抛异常,poll()返回null
boolean remove(Object o)
:删除队列中跟o相等的某一个元素(如果有多个相等,只删除一个)
位运算总结
1. x&(x-1)
表示将x的最后一个1变成0,例如4&(4-1)表示将100变成000、3&(3-1)表示将11变成10
String可以当成“栈”
有很多操作String的题目(例如leetcode1047)。别忘了StringBuffer和StringBuilder自带的方法,可以实现和栈相同的操作,但是比栈更省时间:
sb.charAt(end) -> stack.peek()
sb.append() -> stack.push() 或 stack.add()
sb.charAt(end) + sb.deleteCharAt(end) -> stack.pop()
其中sb是一个StringBuffer/StringBuilder实例