-
/** * 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* head=new ListNode; ListNode* p=head; ListNode* res=head; while(list1 && list2){ if(list1->val<=list2->val){ ListNode* temp=new ListNode; p->next=temp; temp->val=list1->val; p=p->next; list1=list1->next; } else{ ListNode* temp=new ListNode; p->next=temp; temp->val=list2->val; p=p->next; list2=list2->next; } } if(list1==nullptr && list2!=nullptr){ p->next=list2; } else if(list1!=nullptr && list2==nullptr){ p->next=list1; } return res->next; } };
总结:当你需要创造一条新链表的时候,可以使用虚拟头结点简化边界情况的处理。
-
/** * 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* partition(ListNode* head, int x) { ListNode* head1=new ListNode; ListNode* res=head1; ListNode* head2=new ListNode; ListNode* res2=head2; ListNode* x_node=new ListNode; x_node->val=x; while(head){ if(head->val<x){ ListNode* temp=new ListNode; temp->val=head->val; head1->next=temp; head1=head1->next; } else{ ListNode* temp=new ListNode; temp->val=head->val; head2->next=temp; head2=head2->next; } head=head->next; } head1->next=res2->next; return res->next; } };
-
/** * 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) {} * }; */ bool cmp(ListNode* p1,ListNode* p2){ if(p1->val>p2->val){ return true; } else{ return false; } } class Solution { public: /*bool cmp(ListNode* p1,ListNode* p2){ if(p1->val>p2->val){ return true; } else{ return false; } }*/ ListNode* mergeKLists(vector<ListNode*>& lists) { ListNode* head=new ListNode;//虚头节点 ListNode* res=head; /*创建小根堆*/ priority_queue<ListNode*,vector<ListNode*>,decltype(&cmp)> pq(cmp); /*将ListNode放入小根堆中*/ int len=lists.size(); for(int i=0;i<len;i++){ if(lists[i]!=nullptr){ pq.push(lists[i]); } } /*开始循环*/ while(!pq.empty()){ ListNode* temp=pq.top(); pq.pop(); ListNode* node=new ListNode; node->val=temp->val; head->next=node; head=head->next; if(temp->next){ pq.push(temp->next); } } return res->next; } };
用到 优先级队列(二叉堆),优先队列
pq
中的元素个数最多是k
,所以一次poll
或者add
方法的时间复杂度是O(logk)
;所有的链表节点都会被加入和弹出pq
,所以算法整体的时间复杂度是O(Nlogk)
,其中k
是链表的条数,N
是这些链表的节点总数。 -
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
/** * 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=new ListNode; dummy->next=head; ListNode* p1=head; ListNode* p2=dummy; /*p1向前走n步*/ for(int i=1;i<=n;i++){ p1=p1->next; } /*p1,p2一起向前走*/ while(p1){ p1=p1->next; p2=p2->next; } p2->next=p2->next->next; return dummy->next; } };
虽然时间复杂度都是
O(n),但是要感受一下双指针的用法
-
/** * 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) { if(head->next==nullptr){return head;} if(head->next->next==nullptr){return head->next;} ListNode* fast=head; ListNode* slow=head; while(fast && fast->next){ slow=slow->next; fast=fast->next->next; } return slow; } };
感觉是上一道题的小喽啰
-
/** * 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) { if(head==nullptr || head->next==nullptr || head->next->next==nullptr){return nullptr;} bool flag=0; ListNode* fast=head; ListNode* slow=head; while(fast && fast->next && fast->next->next && slow && slow->next && slow->next->next){ slow=slow->next; fast=fast->next->next; if(fast==slow){flag=1;break;} } if(flag==0){return nullptr;} slow=head; while(slow!=fast){ slow=slow->next; fast=fast->next; } return slow; } };
环形链表很好判断,这里就不写代码了(快慢指针最后相遇则有环),找终点的思路如下:首先找到快慢指针的相遇点,然后将慢指针返回起点,二者再次相遇的地方就是环形起始位置。
-
160. 相交链表 - 力扣(LeetCode)本题将用两个写法来写,第一种是用哈希法(回顾一下unordered_map的用法),第二种还是双指针用法(不太好想,p1先遍历A串,再遍历B串;p2先遍历B串,再遍历A串) 第一种写法:
/** * 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) { unordered_map<ListNode*,bool> hmap; while(headA){ hmap[headA]=1; headA=headA->next; } while(headB){ if(hmap.find(headB)!=hmap.end()){ return headB; } headB=headB->next; } return nullptr; } };
第二种写法:
/** * 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* p1=headA; ListNode* p2=headB; //最后p1和p2都会为空 while(p1!=p2){ if(p1==nullptr){ p1=headB; } else{ p1=p1->next; } if(p2==nullptr){ p2=headA; } else{ p2=p2->next; } } if(p1==nullptr){return nullptr;} else{ return p1; } } };
接下来更新5道链表思想题目,找找感觉~
参考:
双指针技巧秒杀七道链表题目 | labuladong 的算法笔记c++优先队列(priority_queue)用法详解-CSDN博客c++优先队列priority_queue(自定义比较函数)_c++ priority_queue自定义比较函数-CSDN博客