常用 API
map的相关操作:
1.将 values 转化为 list 和数组
Collection valueCollection = map.values();
final int size = valueCollection.size();
List valueList = new ArrayList(valueCollection);
String[] valueArray = new String[size];
map.values().toArray(valueArray); //注意数组和 List 的类型必须相同,如List不能转 int[],只能转 Integer[]
Integer[] intArr = list.toArray(new Integer[list.size()]);
StringBuilder
sb.deleteCharAt(sb.length()-1);
String
s.trim() //去除首尾空格
s.split("\\s+"); //正则表达式匹配多个空格
String.join(" ",list);
// 除去开头和末尾的空白字符
s = s.trim();
// 正则匹配连续的空白字符作为分隔符分割
List wordList = Arrays.asList(s.split("\\s+"));
Collections.reverse(wordList);
return String.join(" ", wordList);
String.compareTo()//如果两个字符的ASC码相等则继续后续比较,否则直接返回两个ASC的差值。如果两个字符串完全一样,则返回0
"abcd".compareTo("adef")== -2
"abc".compareTo("abcdef")== -3
"abc".compareTo("abc") == 0
List 相关操作
之前一直只用过 Arrays.sort(nums,comp)对数组排序。这次做45题(要先将 int[]数组转为 Integer[],才能用 Arrays.sort)发现:(1)可以将 int[]转为 List ,直接用 Collections.sort(list,comp) (2)不需要重写 comparator,可以使用 java8提供的 lamda 新特性
Arrays 相关操作
1、Arrays.sort对数组排序,重写 comparator
Comparator com=new Comparator(){
@Override
public int compare(int[] a,int b[]){
return a[0]-b[0]; //如果想让前面的数字比后面的数字小,就返回负的
}
};
Arrays.sort(intervals,com);
使用lamda 表达式: Arrays.sort(intervals,(a,b)->(a-b))
或者直接写成:Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
Arrays.sort()中 Comparator对象的范型不能为 int,只能为 Integer,也就是只能在对 Integer数组排序时,重写 Comparator或者 lamda 表达式
2、int[] 数组无法直接用 Arrays.asList转换成 List, 因为Arrays.asList 传入的对象必须是对象数组(Integer[]数组)
(1)java8以及以上版本可以使用:List list1 = Arrays.stream(array).boxed().collect(Collectors.toList());
(2)导入apache commons-lang3 jar : List list = Arrays.asList(ArrayUtils.toObject(array));
3、int[] 没办法用 Arrays.asList直接转换为 List,而又要将 r add 到List> result中,可以直接将 r 保存在 List 中,利用 Collections.swap(list,i,j) 对 list 的两元素进行交换,然后利用 result.add(new LinkedList(list))
List> result=new LinkedList>();
LinkedList l=new LinkedList<>();
result.add(new LinkedList(l);
Collections.swap(l,index,j); //要用 swap 操作的,用ArrayList!!!!(性能提升)
4、List可以直接转 int[][]
List results;
results.toArray(new int[results.size()][]);
5、对于要求返回 int[]数组,而数组大小未知的情况。之前是使用 List 先动态保存结果,后面再进行转换(List转 int[]不能用 .toArray,只能用 for 循环)。可以先声明一个大范围数组,然后使用 Arrays.copyOfRange(数组地址,首,尾+1)来进行数组的拷贝(性能会提升很多),如下面的(349题)时间从39/6%到99/27%。
class Solution {
//Arrays.copyOfRange(intersection, 0, index);从大数组中截取小数组(代替 List 转 int[]),性能提高两倍
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
//Set<Integer> result=new HashSet<>();
int[] bigResult=new int[nums2.length+nums1.length];
int i=0,j=0;
int index=0;
while(i<nums1.length&&j<nums2.length){
if(nums1[i]==nums2[j]){
if(index==0||bigResult[index-1]!=nums1[i]){
bigResult[index]=nums1[i];
index++;
}
//result.add(nums1[i]);
i++;
j++;
}else if(nums1[i]<nums2[j]){
i++;
}else{
j++;
}
}
/*
int[] r=new int[result.size()];
Iterator<Integer> it=result.iterator();
int k=0;
while(it.hasNext()){
r[k]=it.next();
k++;
}
return r;
*/
return Arrays.copyOfRange(bigResult,0,index);
}
}
PriorityQueue
Queue<Integer> queue = new PriorityQueue<>(7, compare);
//匿名Comparator实现
Comparator<Integer> compare = new Comparator<Integer>(){
@Override
public int compare(Integer c1, Integer c2) {
return (int) (c1 - c2);
}
};
技巧点(节省时间、空间):
1.while(size--)在层序遍历中的应用
层序遍历时不要用两个队列来回替换,用 size,节省空间
https://leetcode-cn.com/problems/binary-tree-right-side-view/
2.利用位移表示 int 的左右范围(int 4字节,32位:1位表示正负,31位表示数字)
(1)最小值:1<<31,-2147483648
(2)最大值:(1<<31)-1 ,2147483647 注意:(1<<31一定要加括号——1<<31-1 表示1<<30,1073741824)
3、需要对 list 调用 get(i)、swap等访问方法时,应该使用 ArrayList 取代 LinkedList
性能会提升很多(如leetcode 207:使用ArrayList,而不是 LinkedList(性能从10%提升到98%。。。。))
4、字符串相加保持代码简洁的方法:67.二进制求和
class Solution {
//代码简洁:
//关键1:可以通过 sum 分段加以及 aI--的形式,使得代码变得简洁(原始冗长代码:(1)如果没有 a b 置换保证 a 指向更长的字符串的话,需要三个循环体;(2)如果保证 a 指向更长的字符串的话,需要两个循环体)
//关键2:在修改 flag 时,可以直接利用除法/2 ,如果 sum>=2则 sum/2肯定为1,反之为0
public String addBinary(String a, String b) {
//a 更长
// if(a.length()<b.length()){
// String temp=a;
// a=b;
// b=temp;
// }
int aI=a.length()-1;
int bI=b.length()-1;
int cI=0;
StringBuilder sb=new StringBuilder();
int flag=0;
while(aI>=0||bI>=0){
int sum=flag;
if(aI>=0) sum+=a.charAt(aI--)-'0';
if(bI>=0) sum+=b.charAt(bI--)-'0';
//ca = sum / 2;
/*
if(sum>=2){
flag=1;
}else{
flag=0;
}
*/
//关键2:简化代码
flag=sum/2;
sb.append(sum%2);
}
if(flag==1) sb.append(1);
return sb.reverse().toString();
}
}
栈的创建
不要使用Stack s=new Stack(); 原因:Stack 类实现了 Vector 接口,Vector底层 是一个 Object 数组,在进行 stack.push 和 pop 时需要进行扩容、数组复制等操作,效率低下。
可以直接声明 LinkedList stack=new LinkedList<>(); 能够直接调用栈的 push 和 pop 操作。
LinkedList push 源码:
public void push(E e) {
addFirst(e);
}
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
pop 源码:
public E pop() {
return removeFirst();
}
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
易错点(bug)
1、回溯算法没有回置
回溯算法必须将回溯部分置为原始值(即使下一个值会覆盖),因为有可能在更高的回溯的时候,逻辑要判断当前的值是否为某个符号(如'.'),如果在之前曾经把点变成数字,二没有抹除的话,在回溯后重新递归到这里的时候,会因为逻辑判断而略过对该位置的赋值
2、双层循环只记得对内层 break(逻辑为双层都 要break )leetcode-556题
class Solution {
public void swap(char[] cs,int i,int j){
char temp=cs[i];
cs[i]=cs[j];
cs[j]=temp;
}
public int nextGreaterElement(int n) {
// 596875
//4632 597865 //4632 7896
//4632 6879
//4632 6789
//4632 7689
int[] numIndex=new int[10];
char[] cs=String.valueOf(n).toCharArray();
for(int i=0;i<cs.length;i++){
numIndex[cs[i]-'0']=i;
}
int k=-1;
for(int i=cs.length-2;i>=0;i--){
for(int num=cs[i]-'0'+1;num<=9;num++){
if(numIndex[num]>i){
swap(cs,i,numIndex[num]);
k=i;
break;
}
}
if(k!=-1) break; //bug:忘写这一句了。双层循环只对内层 break,外层继续运行
}
if(k==-1) return -1;
//对 k 之后的 reverse
int result=0;
int MAX_VALUE=(1<<31)-1;
for(int i=0;i<=k;i++){
if(result>(MAX_VALUE/10)||result==(MAX_VALUE/10)&&cs[i]-'0'>7){
return -1;
}
result=result*10+cs[i]-'0';
}
for(int i=cs.length-1;i>k;i--){
if(result>(MAX_VALUE/10)||result==(MAX_VALUE/10)&&cs[i]-'0'>7){
return -1;
}
result=result*10+cs[i]-'0';
}
return result;
}
}