题目
203. 移除链表元素
要点:使用虚拟头节点dummy,可以用一种统一的方式处理所有节点。
注意对链表节点操作要找到 要处理的节点的前一个结点。
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode cur = dummyhead;
while(cur.next != null){
if(cur.next.val == val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return dummyhead.next;
707. 设计链表
都是基础操作,链表逻辑的一道很好的复习题。要点:
- 用size参数记录链表节点数,每次操作完记得size++或size--;
- 使用虚拟头节点
dummy,记得链表初始化时对dummy的操作。
class MyLinkedList {
//size存储链表元素的个数
int size;
//虚拟头结点
ListNode dummy;
//初始化链表
public MyLinkedList() {
size = 0;
dummy = new ListNode(0);
}
206. 反转链表
如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。
其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。
方法1.双指针 从前往后翻转指针指向
首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。从前往后遍历链表改变指针指向,最后返回pre;
ListNode prev = null;
ListNode cur = head;
ListNode temp = null;
while (cur != null) {
temp = cur.next;// 保存下一个节点
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
方法2. 根据双指针方法的递归从前往后翻转指针指向
方法3. 递归从后往前翻转指针指向
ListNode* reverseList(ListNode* head) {
// 边缘条件判断
if(head == NULL) return NULL;
if (head->next == NULL) return head;
// 递归调用,翻转第二个节点开始往后的链表
ListNode *last = reverseList(head->next);
// 翻转头节点与第二个节点的指向
head->next->next = head;
// 此时的 head 节点为尾节点,next 需要指向 NULL
head->next = NULL;
return last;
}
24. 两两交换链表中的节点
方法1.使用虚拟头节点,指向每次操作的两个节点的前一个节点,从前往后遍历。
方法2.递归
19. 删除链表的倒数第N个节点
快慢指针
要点:
- 使用虚拟头结点,这样方便处理删除实际头结点的逻辑
- fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)
160.链表相交
题目数据 保证 整个链式结构中不存在环。
很简单,先求长度差,长的表先走差值个节点,然后两表一起走,直到节点相等。
## 142.环形链表II
偏数学一些,
1.先通过快慢指针找到相遇节点meet,(从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。)相交点一定在环内;
2.head 和 meet同步走,到相遇时即为入口节点。
总结
递归问题
解递归题的三部曲
- 找整个递归的终止条件:递归应该在什么时候结束?
- 找返回值:应该给上一级返回什么信息?
- 本级递归应该做什么:在这一级递归中,应该完成什么任务?