LinkedList 总结
链表的题基本可以说是基础题,不涉及算法,要熟记他的一些基本操作,基本技巧。
链表的特点就是添加删除O(1),不费空间,比如重新组合一串数字,用array需要从新开一个数组,而链表不需要,只要改变指针就行。
缺点是访问的时候,最坏可能到O(n)。
我个人一般怕乱,所以不用双向表,就用单项表挺好的。
1,dummy大法,在什么情况的时候会引入dummy点呢?一般结构是 dummy.next = head, 所以dummy的作用就是一个伪头节点,在不知道head节点是否会变化的时候需要用dummy标记,以后返回的时候返回dummy.next。一般来说遇到需要head节点会变的时候就需要引入dummy点。
2,快慢指针。快慢指针可以用于:
1)从后向前的链表删除。--快指针先走n步,然后快,慢指针再一起走,当快指针走到头的时候,就找到要删除的位置了。
2)看链表是否有环。--快指针走2步,慢指针走1步,当快慢指针重叠的时候代表有环。此时将慢指针拉回起点,两个指针一起走,再相遇就知道环的长度。
3)找中点。 -- 快走2步,慢走1步,快指针走到头,慢指针正好在1/2处。
基本操作:增(插入),删,查,翻转。
先定义链表(单向):
public class ListNode{
int val;
ListNode next;
ListNode(int val){
this.val = val;
this.next = null;
}
}
-->A-->B-->
1,增加(插入): 在AB中插入节点C
A.next = C;
C.next = B;
2,删除: 删除B节点
while (A.next != null){
A.next =A.next.next;
}
3,查找:value=2的
while (find != null && find.val != 2){
find = find.next;
}
4, 翻转:
while (head != null){
ListNode temp = head.next;
head.next = prev;
prev = head;
head = temp;
}
prev-->A-->B-->C prev先在A点之前(prev),然后防止以后找不到A.next(也就是B)要先拿个pointer记录下这个位置。然后操作A.next(也就是head.next)指向之前的点prev。
prev<--A (temp)-> B --> C 这时候A,B时断开的,肯定要再把B连到A上,那么这时候把prev移到A点,head移动到B上,准备下一次翻转。
常见错误:
1,构建一个链表时候,要有头节点(为了找到链表),还有有个tail节点,尾节点->null,tail.next = null
2, while loop里面,什么时候用while (head != null){} 什么时候用 while (head.next != null){} ANS: 我个人的理解是这样:如果要把所有点都遍历一遍,那肯定是要做head != null判断,如果快慢指针的时候,还要加上fast.next != null。因为,指针head也好,curr也好,都是可以为null的,但是null是不会有next指针,null.next操作时非法的。如果要做删除,肯定是要判断head.next != null;
3, 做删除操作的时候,一定要去判断curr.next是不是要删的,以为单链表一定要记录要删除的前面的点才可以删除,所以curr要从dummy位置开始判断,这样curr.next才是从head开始的。
4, 做递归时,不能直接把一个curr当作入参进入helper函数,这时有两个解决办法:1,定义一个实参,作为全局变量,把这个传入helper,但是不建议,这样不安全;2, 定义一个类,CurrNode,在里面定义一个node,用的时候要申请一个node,传入helper,用的时候记住要currNode.node才能用这个node。
浙公网安备 33010602011771号