1 基础巩固
链表的最基础的知识需要掌握 头插法、尾插法 及 查找中间结点。有了这些最基本操作,才能应对更复杂的题目。
1.1 尾插法
ListNode *tail_insert(ListNode *head) {
ListNode *dummy = new ListNode(-1);
ListNode *tail = dummy;
while (head != NULL) {
ListNode *pnode = head;
head = head->next;
pnode->next = NULL;
tail->next = pnode;
tail = tail->next;
}
return dummy->next;
}
1.2 头插法
ListNode *head_insert(ListNode *head) {
ListNode *dummy = new ListNode(-1);
ListNode *tail = dummy;
while (head != NULL) {
ListNode *pnode = head;
head = head->next;
pnode->next = tail->next; //与尾插区别1
tail->next = pnode;
//tail = tail->next; //与尾插区别2
}
return dummy->next;
}
1.3 发现中间结点
ListNode *find_mid(ListNode *head) {
if (head == NULL) {
return NULL;
}
ListNode *slow = head, *fast = head->next;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
2 解题技巧
2.1 DummyNode
所谓DummyNode其实就是带头结点的指针,使用DummyNode的好处时,当我们不确定所求链表真正的头结点时,先以DummyNode作为头结点,然后依次增长链表。在上面尾插法建表与头插法建表过程中都用到了DummyNode。在解决很多链表问题时,当头结点不确定时,使用DummyNode都可以简化代码,如 remove duplicate node。
2.2 快慢指针
两个指针思想在解决很多问题时都有体现,比如在解决数组问题时,经常用两个指针将数组分段,再讨论段与段之间的关系,如微软机试题目array patition与tow sum。
同样,在解决很多链表问题时,因为链表只能向后访问, 不能向前访问,所以我们通常会在之前设置一个指针记录一些之前的信息。比如需要寻找中点结点,需要两个速度不同的快慢指针。比如寻找倒数第K个元素,需要设定两个指针,一前一后。再比如,需要寻找中点的前一个结点,则需要在slow之前记录一个pre_slow指针,与slow指针同步。
2.3 Segmentation fault
这个问题在解决链表相关问题时经常会遇到,这是因为:在解决链表问题时,经常会用到pnode->val,pnode->next等等操作,但是使用前一定要现判断pnode首先自身不能指向NULL,这就是为什么程序刚开刚始一定要先考虑特殊情况:head == NULL ?,因为后面肯定会用来head->next。另外,链表问题程序很容易出现segmentation falt,一般也是判处每个使用成员操作符的指针本身是否是空指针。
3 经典题目
sort list by quick sort
linked list cycle II:这道题目需要背一下答案
merge k sorted list:总结一个priority_queue的常规用法,参考
copy list with random pointer:练习hashmap解法
convert list to BST:使用O(n)复杂度的方法来解决