24、两两交换链表中的节点
/** * 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个节点三个指针 涉及到 最后三个 两两节点 cur指向 末尾三个两两节点的 第一个两两节点的第一个节点 temp指向 末尾三个两两节点的 第二个两两节点的第一个节点 temp1指向 末尾三个两两节点的 第三个两两节点的第一个节点 例: 1 2 3 4 5 6 第三个两两节点的第一个节点为空 */ class Solution { public: ListNode* swapPairs(ListNode* 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; } };
25. K 个一组翻转链表
题解链接:看的评论的第一个,觉得最好理解
带注释的他人的题解:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode reverseKGroup(ListNode head, int k) { if (head == null || head.next == null){ return head; } //定义一个假的节点。 ListNode dummy=new ListNode(0); //假节点的next指向head。 // dummy->1->2->3->4->5 dummy.next=head; //初始化pre和end都指向dummy。pre指每次要翻转的链表的头结点的上一个节点。end指每次要翻转的链表的尾节点 ListNode pre=dummy; ListNode end=dummy; while(end.next!=null){ //循环k次,找到需要翻转的链表的结尾,这里每次循环要判断end是否等于空,因为如果为空,end.next会报空指针异常。 //dummy->1->2->3->4->5 若k为2,循环2次,end指向2 for(int i=0;i<k&&end != null;i++){ end=end.next; } //如果end==null,即需要翻转的链表的节点数小于k,不执行翻转。 if(end==null){ break; } //先记录下end.next,方便后面链接链表 ListNode next=end.next; //然后断开链表 end.next=null; //记录下要翻转链表的头节点 ListNode start=pre.next; //翻转链表,pre.next指向翻转后的链表。1->2 变成2->1。 dummy->2->1 pre.next=reverse(start); //翻转后头节点变到最后。通过.next把断开的链表重新链接。 start.next=next; //将pre换成下次要翻转的链表的头结点的上一个节点。即start pre=start; //翻转结束,将end置为下次要翻转的链表的头结点的上一个节点。即start end=start; } return dummy.next; } //链表翻转 // 例子: head: 1->2->3->4 public ListNode reverse(ListNode head) { //单链表为空或只有一个节点,直接返回原单链表 if (head == null || head.next == null){ return head; } //前一个节点指针 ListNode preNode = null; //当前节点指针 ListNode curNode = head; //下一个节点指针 ListNode nextNode = null; while (curNode != null){ nextNode = curNode.next;//nextNode 指向下一个节点,保存当前节点后面的链表。 curNode.next=preNode;//将当前节点next域指向前一个节点 null<-1<-2<-3<-4 preNode = curNode;//preNode 指针向后移动。preNode指向当前节点。 curNode = nextNode;//curNode指针向后移动。下一个节点变成当前节点 } return preNode; } }
自己写的:
/** * 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) {} * }; */ /* codetop 高频题第四道,和两两一组反转链表在一起 此题解最好懂 https://leetcode.cn/problems/reverse-nodes-in-k-group/solutions/10416/tu-jie-kge-yi-zu-fan-zhuan-lian-biao-by-user7208t/?orderBy=hot 三个指针:pre代表要反转的链表段的前一个节点, start代表要反转的链表段的链表头, end代表要反转的链表段的链表尾 其中nextL代表下一个链表的链表头,end->next=nextL; */ class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { ListNode *L=new ListNode(-1); L->next=head; ListNode *pre=L,*end=L; while(end->next!=nullptr) { ListNode *start=pre->next; int t=k; while(t && end!=nullptr) { end=end->next; t--; } ListNode *nextL=nullptr; if(end==nullptr) { break; } nextL=end->next; end->next=nullptr;//断开第一个链表 pre->next=reverseList(start); start->next=nextL; pre=start; end=start; } return L->next; } ListNode *reverseList(ListNode *head) { ListNode *slow=nullptr, *fast=head; while(fast!=nullptr) { ListNode *temp=fast; fast=fast->next; temp->next=slow; slow=temp; } return slow; } };
/** * 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) { /* 找倒数第n+1个节点,则fast先多走n+1步,由于有头节点,只需要先走n步就可以 如果用快慢指针,则fast先走n步就可以 */ ListNode *L=new ListNode(-1); L->next=head; ListNode *fast=L,*slow=L; while(n && fast !=nullptr) { fast=fast->next; n--; } if(fast==nullptr) { return nullptr; } while(fast!=nullptr && fast->next!=nullptr) { fast=fast->next; slow=slow->next; } slow->next=slow->next->next; return L->next; } };
面试题 02.07. 链表相交
本题没有视频讲解,大家注意 数值相同,不代表指针相同。
题目链接/文章讲解:代码随想录
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /* 依照我破旧的记忆, 是先走了第一个链表,比如有n1个, 再走第二个链表,比如有n2个, 长的那个先走n2-n1步,再同时往前走,如果节点相同则相交,否则nullptr */ ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *first=headA; ListNode *second=headB; int n1=0; while(first!=nullptr) { first=first->next; n1++; } int n2=0; while(second!=nullptr) { second=second->next; n2++; } int n=0; first=headA; second=headB; if(n2>=n1) { n=n2-n1; while(n) { second=second->next; n--; } } else { n=n1-n2; while(n) { first=first->next; n--; } } while(first!=nullptr && second!=nullptr && first!=second) { first=first->next; second=second->next; } return second; } };
142.环形链表II
算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接/文章讲解/视频讲解:代码随想录
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /* 这个题,只是大概有印象,先找到在环里的相遇节点,至于找到相遇节点后, 那个公式没有特别弄明白,还得是代码随想录的视频版啊 有两个需要注意的地方,一是slow指针必定在环中转不到一圈就被fast追上 二是理解从相遇节点和链表头节点同时同速出发,必定在 有环的第一个index节点相交 */ ListNode *detectCycle(ListNode *head) { if(head==nullptr || head->next==nullptr) { return nullptr; } ListNode *slow=head; ListNode *fast=head; while(fast!=nullptr && fast->next!=nullptr) { slow=slow->next; fast=fast->next->next; if(fast==slow)//如果相等,代表有环 { // cout<<fast->val<<endl; ListNode *index1=head; ListNode *index2=fast; while(index1!=index2) { index1=index1->next; index2=index2->next; } return index1; } } return nullptr; } };