1. 关于集合
(1) 关于map
遍历map:https://www.cnblogs.com/imzhj/p/5981665.html
感觉最好记的方法是这个:
Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}
关于get方法的一个注意点:
if (!map.containsKey(keyStr)) map.put(keyStr, new ArrayList<String>());
map.get(keyStr).add(s); // map的get返回的不是一个副本,而是引用,所以直接修改就好,不需要修改后再put。对于基本类型是不可以这么做的
(2) set集合的增删改元素方法和List集合是一样的吗?remove方法的一个疑问
一样的,都是 add 和 remove 方法,只不过list的remove方法能按照index来删,而set只能按照Object来删。这里有一个长久以来的疑问是如果List集合中放入的是int型元素的话,如果此时使用remove方法,传入int的 话是按照索引来删除元素还是按照int的值来删除元素的呢?
测试结果是还是按照索引来删,如果使用 (Integer)3 这种方式将int包装为Integer的话就会按照值去删。
(3) set和list集合怎么和数组互转?
参考: https://blog.csdn.net/my_precious/article/details/53010232
(4) 关于PriorityQueue的用法
首先要明白的是这个数据结构的特点,这个数据结构使得我们在往队列中加入元素时,虽然是乱序加入,但是队列中始终能够以某种优先级排列队列中的元素。 要注意一点的是
并非像TreeMap一样完全有序,但是如果按照指定方式出队,结果可以是有序的。意思是不能保证队列是有序的,但是可以保证每次出队列出的是最小或最大的元素,这样以此出队才能保证有序
此队列的头 是按指定排序方式确定的最小 元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列获取操作 poll
、remove
、peek
和 element
访问处于队列头的元素。
注意,此实现不是同步的。如果多个线程中的任意线程修改了队列,则这些线程不应同时访问 PriorityQueue
实例。相反,请使用线程安全的 PriorityBlockingQueue
类。
实现注意事项:此实现为排队和出队方法(offer
、poll
、remove()
和 add
)提供 O(log(n)) 时间;为 remove(Object)
和 contains(Object)
方法提供线性时间;为获取方法(peek
、element
和 size
)提供固定时间。
代码示例
public class PriorityQueueTest { public static void main(String[] args) { final PriorityQueue<Student> queue=new PriorityQueue<>(); Student p1=new Student(95,"张三"); Student p2=new Student(89,"李四"); Student p3=new Student(89,"李四"); Student p4=new Student(67,"王五"); Student p5=new Student(92,"赵六"); queue.add(p1); queue.add(p2); queue.add(p3);//add 和offer效果一样。 queue.offer(p4);//add 方法实现,其实就是调用了offer queue.offer(p5) for (Student Student : queue) { System.out.println(Student.toString()); } System.out.println("---------------------"); while(!queue.isEmpty()){ System.out.println(queue.poll()); } } } class Student implements Comparable{ private int score; private String name; public Student(int age,String name){ this.score=age; this.name=name; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return "姓名:"+name+"-"+score+"分"; } @Override public int compareTo(Object o) { Student current=(Student)o; if(current.getScore()>this.score){ return 1; }else if(current.getScore()==this.score){ return 0; } return -1; } }
运行结果
姓名:张三-95分 姓名:赵六-92分 姓名:王五-67分 姓名:李四-89分 ---------按顺序出队选座位------------ 姓名:张三-95分 姓名:赵六-92分 姓名:李四-89分 姓名:李四-89分 姓名:王五-67分
逻辑上使用堆结构(完全二叉树)实现,物理上使用动态数组实现。 参考:https://blog.csdn.net/qq_35326718/article/details/72866180 https://blog.csdn.net/u013309870/article/details/71189189
(5) 比较器
Queue<Integer> pq=new PriorityQueue<Integer>(new Comparator<Integer>(){
public int compare(Integer a, Integer b){ // 这里要严格写成和上面的一样
return b-a;
}
});
原来上面的compare方法中参数类型写成了 int, 以为也能编译通过,结果不行,要严格和Comparator中的泛型一致。自定义了比较器后就可以在Collections和Arrays的sort方法对容器中的元素进行排序,默认是升序排序的。
另两种比较器的使用形式:
public class LeetCode{
public static void main(String[] args){
List<MeetingTime> list=new ArrayList<>();
MeetingTime m1=new MeetingTime(10,30);
MeetingTime m2=new MeetingTime(5,10);
list.add(m1);
list.add(m2);
Collections.sort(list);
}
}
// 让一个类实现Compable接口,然后在集合中就可以直接比较这个元素了,也就是定义类的时候自带比较器
class MeetingTime implements Comparable<MeetingTime>{
int startTime;
int endTime;
public void MettingTime(int startTime, int endTime){
this.startTime=startTime;
this.endTime=endTime;
}
@Override
public int compareTo(MeetingTime m){
return this.startTime-m.startTime;
}
}
public class LeetCode{
public static void main(String[] args){
List<MeetingTime> list=new ArrayList<>();
MeetingTime m1=new MeetingTime(10,30);
MeetingTime m2=new MeetingTime(5,10);
list.add(m1);
list.add(m2);
Collections.sort(list, new MyComparator());
}
// 单独定义一个实现Comparator接口的类,即单独弄一个通用的比较器,避免内部类不能复用的问题
static class MyComparator implements Comparator<MeetingTime>{
@Override
public int compare(MeetingTime t1, MeetingTime t2){
return t1.startTime-t2.startTime;
}
}
}
class MeetingTime {
int startTime;
int endTime;
// 默认的构造函数是没有返回值的
public MeetingTime(int startTime, int endTime) {
this.startTime = startTime;
this.endTime = endTime;
}
}
上面用到了静态内部类的形式,这里复习下java静态类和非静态类的区别:https://www.cnblogs.com/muffe/p/6580208.html
(6) List在指定位置插入
void add(int index, E element);
2. 关于字符和字符串,不同类型的数字
String判断相等要用equals方法,不能直接用等号。
利用trim()方法可以快速去除字符串的前导空白和尾部空白
(1) 相互转换
int转String直接加""即可,String转int需要用到Integer.parseInt()方法。
String转char数组直接调用toCharArray()方法,
String与char互转,例如将“49”转化成‘49’
char与int互转。
package CodeTest;
public class LeetCode {
// int, char, String互转测试
public static void main(String[] args) {
int int49 = 49;
int int4 = 4;
/*-------int和char互转----------*/
// char c = '49'; 错误,应该是字符串
char char49 = (char) int49; //int -->char
System.out.println((char) char49); // 结果是1,因为49应该转为String,而不是char
//System.out.println((String)char49); 错误,不可以这么用
char char4;
char4 = (char) int4;
System.out.println(char4); //int -->char, 乱码,没有转成功
char4 = (char) (int4 + 48);
System.out.println(char4); //成功输出4,上面要加强转,否则编译不通过
int4 = char4 - '0';
System.out.println(int4); //char -->int, 直接减去字符0就可以了
/*-------int和String互转----------*/
System.out.println(String.valueOf(4));
System.out.println(Integer.parseInt("4"));
/*-------String和char互转----------*/
char[] crs = "test".toCharArray();
String str = String.valueOf(crs);
char chr = '4';
str = String.valueOf(chr); // char -->String
System.out.println(str);
// str="4"; 对于单个字符的String --> char 好像还是只能用toCharArray
}
}
(2) 快速逆转字符串
String reversed = new StringBuilder(s).reverse().toString()
(3) split和replaceAll按多个字符串匹配
// 这里用“|”来匹配多个替换,对于中括号,前面要加上转义字符 \\ String str=input.replaceAll(",| |\\]|\\[","");
(4) double, long, int
做算法题时遇到一个比较尴尬的问题,用到Math.pow()这个函数求指数的时候,因为它返回的是double,结果之前的变量用的是int或long,结果编译阶段各种出错,现在来总结下遇到的转换方式
int mod = (int)Math.pow(10, 9) + 7
// long res; int mod
return (int) (res % mod); // 正确
return (int) res % mod; // 错误,编译不通过
3. DFS&BFS&DP
BFS和DFS遍历时不要忘记加visited数组来标记已经访问过的数组,否则会重复遍历。
关于dp的一个心得:dp分为自顶向下和自低向上,其实两者都是从末端的临界开始往另一侧考虑,通俗的说就是从最边上的条件变化入手。
BFS如何出完一层之后,再出下一层?
4. 其它
一些有用的参考代码片断:
nusm[0]=nums[n++]=1; // 可以这么赋值但不可以这么定义
//return new int[2]{i+1,j+1}; 错误,编译不通过不能在此处加2
return new int[]{i+1,j+1};
for(int[] row:dp) Arrays.fill(row, Integer.MIN_VALUE);
int[][] mp = new int[m][26];
Map<String, Integer> dp = new HashMap<>();
for (int i = 0; i < m; i++)
for (char c:stickers[i].toCharArray()) mp[i][c-'a']++
for (int j = 0; j < 26; j++) {
if (tar[j] > 0 )
for (int k = 0; k < Math.max(0, tar[j]-mp[i][j]); k++)
sb.append((char)('a'+j));
}