方法归纳,dummy节点、双指针
代表题型
---------------------------------------------------------------------------------------------------------------
合并两个有序链表
使用dummy节点,然后依次比较插入dummy节点后就行了,时间复杂度O(N),空间复杂度O(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode dummy;
ListNode *p = &dummy;
while (list1 && list2) {
if (list1->val <= list2->val) {
p->next = list1;
list1 = list1->next;
} else {
p->next = list2;
list2 = list2->next;
}
p = p->next;
}
p->next = list1 ? list1 : list2;
return dummy.next;
}
};
合并K个有序链表
思路一样,多一个取k个链表最小值
class Solution {
public:
void insertlist(list<ListNode *> &list1, ListNode *node)
{
for (list<ListNode*>::iterator it = list1.begin(); it != list1.end(); it++) {
if (node->val <= (*it)->val) {
list1.insert(it, node);
return;
}
}
list1.push_back(node);
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
int size = lists.size();
list<ListNode *> list1;
for (int i = 0; i < size; i++) {
if (lists[i] != nullptr)
insertlist(list1, lists[i]);
}
ListNode dummy;
ListNode *p = &dummy;
while (!list1.empty()) {
ListNode *node = list1.front();
list1.erase(list1.begin());
p->next = node;
p = p->next;
if (node->next)
insertlist(list1, node->next);
}
return dummy.next;
}
};
删除倒数第N个元素
双指针方法,注意头节点也可能被删除,所以dummy节点也是必要的
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode dummy;
dummy.next = head;
ListNode *s, *q;
s = q = &dummy;
for (int i = 0; i < n+1; i++) {
if (q == nullptr)
return head;
q = q->next;
}
while (q) {
s = s->next;
q = q->next;
}
s->next = s->next->next;
return dummy.next;
}
};
环形链表
偷了两张图,说的很清楚
第一次相遇,快指针肯定比慢指针多走圆圈的一倍至n倍(理解下,周长固定,只要k足够大,肯定会相遇),对应2图方法就可以找到起始点了
判断是否环形链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *s, *p;
s = p = head;
while (p && p->next) {
p = p->next->next;
s = s->next;
if (p == s) //相遇成环
return true;
}
//有终点,说明不成环
return false;
}
};
判断是否成环,成环就返回入环起始点,否则返回null
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//先相遇
ListNode *s, *f;
s = f = head;
while (f && f->next) {
f = f->next->next;
s = s->next;
if (f == s) break; //成环
}
if (f == NULL || f->next == NULL) return NULL; //不成环
//s重置,s,p速度一致再次相遇即入环点
s = head;
while (f != s) {
f = f->next;
s = s->next;
}
return s;
}
};
链表的中间节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode *s, *f;
s = f =head;
while (f && f->next) {
f = f->next->next;
s = s->next;
}
return s;
}
};
相交链表
通过图片可以得出一个结论相交部分必然在两个链表尾端,那么两个指针相同速度从A走完到B,从B走完到A,必然相交于相交部分的起始位置。假设相交部分长度为C,都走了A+B-C的距离。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *A = headA;
ListNode *B = headB;
while (A != B) {
A = A == NULL ? headB : A->next;
B = B == NULL ? headA : B->next;
}
return A;
}
};