1、合并两个有序链表(leetcode 21 简单)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* head = new ListNode(-1);
ListNode* p = head;
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 == nullptr ? list2 : list1;
return head->next;
}
};
2、合并K个升序链表(leetcode 23 困难)
技巧:使用优先队列,把链表节点放入一个最小堆,就可以每次获得k节点中的最小节点
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* head = new ListNode(-1);
ListNode* p = head;
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 == nullptr ? list2 : list1;
return head->next;
}
};
3、删除链表的倒数第 N 个结点(leetcode 19 中等)
技巧:使用快慢指针p1, p2,首先让p1先走k步,然后p2跟p1一起移动,直到p1走到最后一个节点,那么p2指向了倒k节点(要删除N节点,那么p2只要先走n+1步)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* head = new ListNode(-1);
ListNode* p = head;
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 == nullptr ? list2 : list1;
return head->next;
}
};
4、链表的中间结点(leetcode 876 简单)
技巧:使用快慢节点low、fast,fast每次走两步,low每次走一步,当fast走到最后一个节点,那么low就是中间节点(注意:如果链表长度是偶数,low指向的右边那个节点)
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* low = head, *fast = head;
while(fast && fast->next != nullptr)
{
low = low->next;
fast = fast->next->next;
}
return low;
}
};
5、判断是否环形链表(leetcode 141 简单)
技巧:使用快慢指针fast、low,fast每走两步,low走一步,如果快慢指针相遇(fast==low),那么就是有环;否则如果fast变为空指针,则无环
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *low = head, *fast = head;
while(fast && fast->next != nullptr)
{
low = low->next;
fast = fast->next->next;
if(low == fast)
return true;//break; //有环
}
return false;
}
};
6、找出环形链表环的起点 II(leetcode 142 中等)
技巧:使用快慢指针fast、low,让fast每走两步,low走一步,如果快指针变成了空指针,那么无环;如果快慢指针相遇(fast == low),那么有环,此时让慢指针重新指向头结点(low=head),快慢指针一起往前走,下次相遇就是环的起点(如图解释):
如果有环,那么到达相遇点low指针走了k步,fast指针走了2k步,多走的部分在环内转圈圈(可得k步为圈大小的整数倍);假设环起点到相遇点为m步,那么相遇点到环起点就是k-m步,又因为head到环起点也是k-m步,所以快慢指针再走k-m步就会在环起点相遇
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *low = head, *fast = head;
while(fast && fast->next != nullptr)
{
low = low->next;
fast = fast->next->next;
if(low == fast)
break; //有环
}
if(fast == nullptr || fast->next == nullptr)
{
return nullptr;
}
low = head;
while(low != fast){
low = low->next;
fast = fast->next;
}
return low;
}
};
7、 相交链表(leetcode 160 简单)
技巧1:使用hastmap记录第一链表的所有节点,让后遍历另一个链表,如果可以在hash中找到则表明他们相交
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_map hashmap;
ListNode* p = headA;
while(p)
{
hashmap[p] = true;
p = p->next;
}
p = headB;
while(p)
{
if(hashmap[p]){
return p;
}
p = p->next;
}
return nullptr;
}
};
进阶,技巧2:假设两个链L1,L2表相交,我们把L1独立部分长度设为len1, L2独立部分长度设为len2, 相交公共部分长度设为len3, 由于等式: len1 + len3 + len2 = len2 + len3 + len1 =>> L1长度(len1 + len3) + L2独立部分(len2) = L2长度(len2 + len3) + L1独立部分len1 ,那么只要使用两个指针p1,p2分别走完上面的路径(p1指向L1,如果遇到nullptr那么指向L2,p2指向L2,如果遇到nullptr那么指向L1),相遇的时候就是交点
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA, *p2 = headB;
while(p1 != p2)
{
if(p1 == nullptr)
p1 = headB;
else
p1 = p1->next;
if(p2 == nullptr)
p2 = headA;
else
p2 = p2->next;
}
return p1;
}
};



