92.反转链表Ⅱ
链接:力扣
一刷,四个指针很重要,可以单独拿出来到函数中好理解。
/** * 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* reverseBetween(ListNode* head, int left, int right) { ListNode *L=new ListNode(-1); L->next=head; //有4个指针需要注意,有没有办法一次遍历? ListNode *p=L,*p1=nullptr,*p2=nullptr,*p3=nullptr,*p4=nullptr; int num=0; while(p!=nullptr) { if(num==left-1) { p1=p; p2=p->next; } if(num==right) { p3=p; p4=p->next; break; } p=p->next; num++; } reverse_list(p1,p2,p3,p4); //cout<<p1->val << " "<<p2->val << " "<<p3->val<< " "<<p4->val<<endl; return L->next; } void reverse_list(ListNode *p1,ListNode *p2,ListNode *p3,ListNode *p4) { ListNode *slow=p4; ListNode *fast=p2; while(fast!=p4) { ListNode *temp=fast; fast=fast->next; temp->next=slow; slow=temp; } p1->next=slow; } };
25.K个一组翻转链表
链接:力扣
跟着一刷走,大概就是每遍历k个就断开,同时记录剩余链表的头节点。
和上面那道题中一样,要反转的链表的前一个结点、要反转链表的第一个节点、要反转链表的最后一个节点、要反转链表的尾节点的下一个节点(同时也是下一个要反转链表的头节点),要特别注意。
/** * 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* reverseKGroup(ListNode* head, int k) { //设置头节点 ListNode *L=new ListNode(-1); L->next=head; //遍历反转 ListNode *pre=L; ListNode *start=pre->next; ListNode *end=pre; int t=k; while(end!=nullptr)//这里为什么是end->next,因为想得到的是k个链表中最后一个节点,如果是end!=null 则到了下一个链表中的第一个节点 { t=k; while(end!=nullptr && t) { end=end->next; t--; } if(end==nullptr)//如果end为nullptr,说明不满k个,最后保持原状 { break; } ListNode *nextstart=end->next; end->next=nullptr;//这个特别重要,必须断开,不然函数内无法执行 pre->next=ReverseList(start); start->next=nextstart; pre=start; start=nextstart; end=pre; } return L->next; } ListNode *ReverseList(ListNode *start) { ListNode *slow=nullptr,*fast=start; while(fast!=nullptr) { ListNode *temp=fast; fast=fast->next; temp->next=slow; slow=temp; } return slow; } };
1、四个节点,且end节点必须从pre开始,而不是start开始
2、每次反转,先让end去探路,如果小于k个,则break
3、反转链表前,必需让end->next=nullptr ,链表断开再反转。否则无法使用ReverseList函数。
21.合并两个有序链表
链接:力扣
不知道几刷,挺简单的。
/** * 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 *L=new ListNode(-1); ListNode *r=L; ListNode *p1=list1,*p2=list2; while(p1!=nullptr && p2!=nullptr) { if(p1->val<p2->val) { r->next=p1; p1=p1->next; } else { r->next=p2; p2=p2->next; } r=r->next; } if(p1!=nullptr) { r->next=p1; } else { r->next=p2; } return L->next; } };
23.合并K个排序链表
链接:力扣
看题解,就很牛,竟然能是优先队列,还是印象模模糊糊的
/** * 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: struct cmp{ bool operator() (ListNode* &node1,ListNode* &node2)//建立一个小根堆 { return node1->val>node2->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) {//把整个链表放入优先队列 priority_queue<ListNode*,vector<ListNode*>,cmp>q; for(auto list:lists) { if(list!=nullptr) { q.push(list); } } ListNode *h=new ListNode(-1),*r=h; while(!q.empty()) { ListNode *temp=q.top();//temp既是链表头结点,又是整个链表 r->next=temp; temp=temp->next;//该链表的头结点换成第二个 q.pop();//把原先的头结点pop掉 if(temp!=nullptr) { q.push(temp); } r=r->next; } return h->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: struct myCompare{ bool operator()(ListNode * &a,ListNode * &b) { return a->val>b->val;//小根堆是>号? } }; ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*,vector<ListNode*>,myCompare>pQueue; for(auto headnode:lists) { if(headnode!=nullptr) { pQueue.push(headnode); } } ListNode *L=new ListNode(-1); ListNode *r=L; while(!pQueue.empty()) { ListNode *temp=pQueue.top();//取出所有链表中头节点最小的,即最小节点 pQueue.pop();//删除拥有最小头结点的链表 r->next=temp;//把最小头节点连接到要求得合并链表 r=r->next; temp=temp->next;//拥有最小头结点的链表,往下走一个节点,再把这个更新后的链表扔进小根堆 if(temp!=nullptr) { pQueue.push(temp); } } return L->next; } };
141.环形链表
链接:力扣
![]()
/** * 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) { if(head==nullptr || head->next==nullptr) { return false; } ListNode *slow=head; ListNode *fast=head->next; while(fast!=nullptr && fast->next!=nullptr) { slow=slow->next; fast=fast->next->next; if(slow==fast) { return true; } } return false; } };
60.相交链表
链接:
![]()
/** * 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; int lenA=0,lenB=0; while(p1!=nullptr) { p1=p1->next; lenA++; } while(p2!=nullptr) { p2=p2->next; lenB++; } int n=abs(lenA-lenB); p1=headA,p2=headB; if(lenA>lenB) { while(n) { p1=p1->next; n--; } } else { while(n) { p2=p2->next; n--; } } while(p1 && p2) { if(p1==p2) { return p1; } p1=p1->next; p2=p2->next; } return nullptr; } };
141.环形链表II
链接:力扣
做过很多遍了,这次没有做
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ /* 有一道题印象深刻,判断两个链表相交的位置。突然发现是这道题!真尴尬 基本思路: 先让fast节点多走两步,!!fast指针是一步走两个节点,slow指针一步走一个节点 然后fast和slow必然在环内相交。记住环内相交节点,然后让第三个指针从链表起始节点出发,相交节点指针和起始指针同步出发,来到环的入口节点 */ class Solution { public: ListNode *detectCycle(ListNode *head) { if(head==nullptr || head->next==nullptr) { return nullptr; } ListNode *fast=head,*slow=head; while(fast!=nullptr && fast->next!=nullptr) { slow=slow->next; fast=fast->next->next; if(slow==fast)//说明有环 { //cout<<"有环"<<endl; ListNode *p=head; while(p!=slow) { p=p->next; slow=slow->next; } return slow; } } return nullptr; } };
143.重排链表
链接:
震惊,基本思路是先反转后半部分,再合并
/** * 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: void reorderList(ListNode* head) { if(head->next!=nullptr) { ListNode *L=new ListNode(-1); L->next=head; int len=0; ListNode *p=head; while(p!=nullptr) { p=p->next; len++; } int t=len/2; p=L; while(p!=nullptr && t) { p=p->next; t--; } cout<<p->val<<endl; ListNode *nextstart=p->next; p->next=nullptr; //反转后半截链表 ListNode *List2= ReverseList(nextstart); /* 调试 PrintList(L->next); cout<<"============="<<endl; PrintList(List2);*/ //合并链表,r为新链表指针 ListNode *p1=L->next, *p2=List2,*r=L; int flag=0; while(p1 && p2) { if(flag) { r->next=p2; p2=p2->next; flag=0; } else { r->next=p1; p1=p1->next; flag=1; } r=r->next; } r->next=p2; head= L->next; } } ListNode* ReverseList(ListNode *fast) { ListNode *slow=nullptr; while(fast!=nullptr) { ListNode *temp=fast; fast=fast->next; temp->next=slow; slow=temp; } return slow; } void PrintList(ListNode *l) { ListNode *p=l; while(p!=nullptr) { cout<<p->val<<" "; p=p->next; } cout<<endl; } };
寻找中点不需要多遍历一遍,用快慢指针即可
class Solution { public: void reorderList(ListNode* head) { if (head == nullptr) { return; } ListNode* mid = middleNode(head); ListNode* l1 = head; ListNode* l2 = mid->next; mid->next = nullptr; l2 = reverseList(l2); mergeList(l1, l2); } ListNode* middleNode(ListNode* head) { ListNode* slow = head; ListNode* fast = head; while (fast->next != nullptr && fast->next->next != nullptr) { slow = slow->next; fast = fast->next->next; } return slow; } ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr != nullptr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } void mergeList(ListNode* l1, ListNode* l2) { ListNode* l1_tmp; ListNode* l2_tmp; while (l1 != nullptr && l2 != nullptr) { l1_tmp = l1->next; l2_tmp = l2->next; l1->next = l2; l1 = l1_tmp; l2->next = l1; l2 = l2_tmp; } } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/LGjMqU/solutions/1037737/zhong-pai-lian-biao-by-leetcode-solution-wm25/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
19.删除链表的倒数第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 { /* 以第一个为例,删除链表的倒数第2个节点相当于找到正数第三个节点 3 2 n len-n 让fast指针先走n步,然后slow再和fast一起走 */ public: ListNode* removeNthFromEnd(ListNode* head, int n) { if(head==nullptr ) { return head; } ListNode *L=new ListNode(-1); L->next=head; ListNode *fast=L,*slow=L; n++; while(n && fast!=nullptr) { fast=fast->next; n--; } while(fast!=nullptr) { slow=slow->next; fast=fast->next; } if(slow!=nullptr && slow->next!=nullptr) { slow->next=slow->next->next; } return L->next; } };
82.删除排序链表中的重复元素|| 中等--------这道题第二遍了还是有些吃力
链接:力扣
错误解法:
/** * 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* deleteDuplicates(ListNode* head) { if(head==nullptr) { return nullptr; } ListNode *L=new ListNode(-1); L->next=head; ListNode *pre=L,*start=L->next,*end=L->next; while(end!=nullptr) { int temp=start->val; end=start->next; while(end!=nullptr && end->val==temp) { endpre=end; end=end->next; } start=end; pre->next=start;//删除重复节点 pre=endpre;//上一个链表的最后一个节点 //下一个循环 end=pre; } return L->next; } };
正确解法:
重点:按照有无重复节点,分类讨论。另外也可以设置pre ,start,end=start->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* deleteDuplicates(ListNode* head) { if(head==nullptr) { return nullptr; } ListNode *L=new ListNode(-1); L->next=head; ListNode *pre=L,*start=L->next,*end=L->next; while(end!=nullptr) { int temp=start->val; end=start->next; if(end!=nullptr && end->val==temp)//有重复元素 { while(end!=nullptr && end->val==temp) { end=end->next; } pre->next=end; start=end; } else//没有重复元素 { pre=start; start=start->next; } } return L->next; } };
速刷剑指offer
83.删除排序链表中的重复元素 ----简单
链接:力扣
这个快慢指针比较快,但是我还是延续了上一次的思路。
一刷:
/** * 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* deleteDuplicates(ListNode* head) { if(head==nullptr) { return nullptr; } ListNode *slow=head,*fast=head->next; while(fast!=nullptr) { if(fast->val==slow->val) { fast=fast->next; } else { slow->next=fast; slow=fast; fast=fast->next; } } slow->next=fast; return head; } };
二刷:
/** * 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* deleteDuplicates(ListNode* head) { ListNode *L=new ListNode(-1); L->next=head; ListNode *pre=L, *fast=L->next; while(fast!=nullptr) { while(fast!=nullptr && fast->next!=nullptr&& fast->val==fast->next->val) { fast=fast->next; } pre->next=fast; pre=fast; if(fast==nullptr) { break; } fast=fast->next; } return L->next; } };
a
148.排序链表 中等
链接:力扣
题解看这篇:力扣
链表的归并排序,真是丧心病狂
要写两个函数,cut(链表,n),把链表的前n个cut下来
merge(链表1,链表2)合并两个有序链表
![]()
这道题真难,啊啊啊啊啊啊啊啊啊
/** * 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 { /* 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序 */ public: ListNode* sortList(ListNode* head) { ListNode *L=new ListNode(-1); L->next=head; //计算链表长度 int len=0; ListNode *p=L->next; while(p!=nullptr) { p=p->next; len++; } //归并排序,cut函数将链表 l 切掉前 n 个节点,并返回后半部分的链表头。 for(int cutsize=1;cutsize<len;cutsize=cutsize*2) { ListNode *tail=L; ListNode *nextList=tail->next; while(nextList!=nullptr) { ListNode *list1=nextList; // cout<<"nextList->val "<<nextList->val<<endl; // cout<<"list1->val "<<list1->val<<endl; ListNode *list2=cut(list1,cutsize);//把头为list1数cutsize个节点cut出去,返回cut完后,后半截的头 nextList=cut(list2,cutsize); /*调试 printL(list1); printL(list2); printL(nextList);*/ tail->next=MergeSort(list1,list2); while(tail->next!=nullptr) { tail=tail->next; } // cout<<"========================="<<endl; } } return L->next; } ListNode *cut(ListNode *l,int n)//必须断开,最后一个元素指向空 { ListNode *p=l; n--;//为了找到末尾节点而不是下一个链表头节点 while(p&& n) { p=p->next; n--; } if(p==nullptr) { return nullptr; } ListNode *nextl=p->next; p->next=nullptr; return nextl; } ListNode *MergeSort(ListNode *l1,ListNode *l2) { //先整一个头结点; ListNode *temp=new ListNode(-1); temp->next=l1; ListNode *p1=l1,*p2=l2,*r=temp; while(p1&& p2) { if(p1->val<p2->val) { r->next=p1; p1=p1->next; } else { r->next=p2; p2=p2->next; } r=r->next; } if(p1) { r->next=p1; } else { r->next=p2; } return temp->next; } };
a
a
24.两两交换链表中的节点 中等 -------再刷还是容易忘,哭哭
链接:力扣
又是麻花君,又见麻花君
首先这个麻花涉及四个节点,同时有一个节点是头节点,所以实际上是三个节点
是个4个节点上的均匀麻花
然后pre一次走一步,pre=temp;
/** * 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) {} * }; */ /* 首先这个麻花涉及四个节点,同时有一个节点是头节点,所以实际上是三个节点 是个4个节点上的均匀麻花 然后pre一次走一步,pre=temp; */ class Solution { public: ListNode* swapPairs(ListNode* head) { if(head==nullptr || head->next==nullptr) { return head; } //头节点 ListNode *L=new ListNode(-1); L->next=head; ListNode *cur=L; while(cur!=nullptr && cur->next!=nullptr && cur->next->next!=nullptr) { ListNode *temp=cur->next; ListNode *temp1=cur->next->next->next; cur->next=temp->next; cur->next->next=temp; temp->next=temp1; cur=temp; } return L->next; } };