链表题目常用方法总结:
- dummy node 常用于链表的head可能被修改或删除的情况,可简化单链表没有前向指针所带来的问题,通常使用current = dummy进行遍历,最终返回 dummy->next
- 链表中尽量避免new新的节点,而是在原链表上直接操作地址
- 在插入和删除操作中使用临时变量来存储next指针
- 反转链表通常需要使用pre指针记录前驱节点
- 通过两个指针几何变换来解决链表长度、环检测等问题
- 对于一些依赖后面节点才能完成的操作,通常使用递归来解决
常见题目:
从尾到头打印链表
反向迭代器rbegin(), rend(),栈,递归
1 | vector<int> printListReversingly(ListNode* head) { |
O(1)时间删除节点
替换下一节点的值,直接删除下一个节点
尾节点只能从头遍历
1 | void deleteNode(ListNode* node) { |
删除重复节点
1 | ListNode* deleteDuplication(ListNode* head) { |
倒数第k个节点
1 | ListNode* findKthToTail(ListNode* head, int k) { |
反转链表
1 | ListNode* reverseList(ListNode* head) { |
合并两个有序单链表
1 | ListNode* merge(ListNode* l1, ListNode* l2) { |
链表归并排序
两个链表的第一个公共节点
假设公共部分长度为c,两个链表同时走a+b+c步,a + c + b = b + c + a,a走到头就转向b, b走到头转向a,则在公共部分相遇
1 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { |
链表环的入口
两指针一快一满,快指针以两倍速度行走,必定相遇在环内
下图x+y必定为环的长度的整数倍,因为2(x+y) = x + y + nlen
此时慢指针回到开头 两指针同时重新走x步均回到b点,即环的入口
1 | ListNode *entryNodeOfLoop(ListNode *head) { |
复杂链表的复制
带random指针的listNode节点的复制
使用哈希表保存random指针的原节点和复制节点对应关系
在原链表上穿叉复制节点