参考:labuladong的算法小抄,自己按照思路手写了一遍 https://labuladong.github.io/algo/di-ling-zh-bfe1b/shuang-zhi-0f7cc/
链表
Checklist
- 如果要创造一个新表,用dummy指针避免空指针的处理情况,代码更简洁
- 分割链表:记得断开原链表的next,否则结果有环
- 快慢指针应用
- 倒数第k个:fast先跑k步,slow开始跑
- 环形链表:fast跑两步,slow跑一步
- 环形链表交点:画图。相交之后把任意一个放到起点再跑,再相交时就是交点
- 两表相交:p1:跑完1再跑2,p2:跑完2再跑1。while(p1!=p2)
leetcode 21: 合并有序列表
https://leetcode.com/problems/merge-two-sorted-lists/
Tips:
- dummy结点的运用,避免处理空指针,让代码更简洁,在创造一条新链表的时候有用
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dummy = new ListNode(-1);
ListNode* p = dummy;
ListNode* l1 = list1;
ListNode* l2 = list2;
while(l1 != NULL && l2 != NULL){
if(l1->val < l2->val){
p->next = l1;
l1 = l1->next;
} else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
if (l1 != NULL) {
p->next = l1;
}
if (l2 != NULL) {
p->next = l2;
}
return dummy->next;
}
};
leetcode 86 partition list(分割链表)
https://leetcode.com/problems/partition-list/
Tips
- 思路:将小于x和大于等于x的节点分别放在两个链表中
- 注意:不能直接p = p->next, 要记得断开原链表中每个结点的next指针,否则最后返回的结果中有环
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* dummy1 = new ListNode(-1);
ListNode* dummy2 = new ListNode(-1);
ListNode* l1 = dummy1;
ListNode* l2 = dummy2;
ListNode* p = head;
while (p != NULL){
if (p->val < x) {
l1->next = p;
l1 = l1->next;
} else {
l2->next = p;
l2 = l2->next;
}
ListNode* temp = p->next;
p->next = NULL;
p = temp;
}
l1->next = dummy2->next;
return dummy1->next;
}
};
leetcode 23 合并K个有序链表
要用到优先队列,有点难。。。先跳过
leetcode 19 删除链表的倒数第k个节点
https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/
思路:遍历一次链表,找到倒数第k个结点,双指针。
- 先让p1跑到k的位置
- 然后p2从头开始和p1一起跑,一直把p1跑到链表结尾,此时p2的位置就是倒数第k个
注意
- 注意虚拟指针的运用,要新建3个指针,dummy和p1和p2,一开始指向head的前一个结点。
- 删除指针的操作,直接p2->next = p2->next->next即可,不用创建临时节点
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode *p1 = dummy, *p2 = dummy;
for(int i=0; i<n; i++){
p1 = p1->next;
}
while(p1!=NULL and p1->next != NULL){
p1 = p1->next;
p2 = p2->next;
}
p2->next = p2->next->next;
return dummy->next;
}
};
leetcode 876 Middle of the linked list(单链表的中点)
https://leetcode.com/problems/middle-of-the-linked-list/description/
快慢指针,没啥好说的
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *p1 = head, *p2 = head;
while (p1 != NULL and p1->next != NULL) {
p1 = p1->next->next;
p2 = p2->next;
}
return p2;
}
};
leetcode 141 Linked list cycle(环形链表)
https://leetcode.com/problems/linked-list-cycle/
快慢指针,没啥好说的
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *p1 = head, *p2 = head;
while (p1 != NULL and p1->next != NULL) {
p1 = p1->next->next;
p2 = p2->next;
}
return p2;
}
};
leetcode 142 Linked List Cycle II (环形链表2)
https://leetcode.com/problems/linked-list-cycle-ii/description/
找出环形链表的起始结点
- 快慢指针找到相交点
- 把任意一个指针放到起点,再相同速度走,再相遇的时候就是环的起点
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *p1 = head, *p2 = head;
int k = 0;
while(p1 && p1->next) {
p1 = p1->next->next;
p2 = p2->next;
if(p1 == p2) {
p1 = head;
while(p1!=p2){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
}
return NULL;
}
};
leetcode 160:Intersection of two linked list(链表是否相交)
https://leetcode.com/problems/intersection-of-two-linked-lists/
双指针,跑完A后,再跑B。如果有交点,两个指针最终会落在交点上;如果没有交点,两个指针都是NULL. 思路是逻辑上让2个指针走同样的距离,消除长短差
代码实现的时候,注意循环条件是while(p1!=p1)即可。这种写法可以覆盖到不相交的的情况。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA, *p2 = headB;
while(p1 != p2) {
if(p1) {
p1 = p1->next;
} else {
p1 = headB;
}
if(p2) {
p2 = p2->next;
} else {
p2 = headA;
}
}
return p1;
}
};