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) {} * }; */ class Solution { public: ListNode* swapPairs(ListNode* head) { if(head == nullptr) return head; // 定义一个虚拟结点,方便操作 ListNode* _dummyHead = new ListNode(0); _dummyHead->next = head; ListNode* cur = _dummyHead; // 判断cur后面有2个非空结点可以进行交换 while(cur->next != nullptr && cur->next->next != nullptr) { // 交换操作 ListNode* tmp = cur->next; ListNode* tmp1 = cur->next->next->next; cur->next = tmp->next; tmp->next->next = tmp; tmp->next = tmp1; cur = tmp; } return _dummyHead->next; } };
遇到的问题:
主要是设计时就出现大问题,一开始未设置虚拟结点,也没考虑偶数链表的尴尬情况,后来优化之后解决问题
19.删除链表的倒数第N个节点
题目链接:力扣
看到题目的第一想法:
这道题由于之前做过还有印象,一下就想到用一个等长窗口通过移动找到倒数第n个结点,实现的时候也没有大问题,可以单独ac
/** * 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个的结点a,然后定义一个从头开始的结点b, // 然后a和b一起往后走,直到a->next为空,这时候b就是倒数第n个结点的前一个结点,删除下一个结点即可 ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* a = dummyHead; while(n--) { a = a->next; } ListNode* b = dummyHead; while(a->next != nullptr) { a = a->next; b = b->next; } // 删除操作 ListNode* tmp = b->next; b->next = b->next->next; delete tmp; return dummyHead->next; } };
遇到的问题:
暂时没有大问题,可以ac
面试题 02.07. 链表相交
题目链接:力扣
看到题目的第一想法:
这道题目由于上一道 19.删除链表的倒数第N个节点 这题给我启发,使用类似的方法来使两个链表等长,逐一判断结点即可,还有就是这道题锻炼了对结点个数的计算,要精准的判断当前结点为空还是当前结点的下一个结点为空,这也算是对于链表的一种熟悉把,由于做过可以单独ac
/** * 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) { int lenA = 0; int lenB = 0; ListNode* curA = headA; ListNode* curB = headB; while(curA != nullptr) { lenA++; curA = curA->next; } while(curB != nullptr) { lenB++; curB = curB->next; } // 使A成为长的那个数组 if(lenB > lenA) { swap(lenA,lenB); swap(headA,headB); } int len = lenA - lenB; curA = headA; curB = headB; while(len--) { curA = curA->next; } // 开始比对A与B是否相等 while(curA != nullptr) { if(curA == curB) { return curA; } curA = curA->next; curB = curB->next; } // 还没找到说明没有 return NULL; } };
遇到的困难:
没有太大的问题,注意结点的数量对比就好啦
142.环形链表II
题目链接:力扣
看到题目的第一想法:
这是一到有难度的题,除暴力之外想要用巧方法解出来有难度,由于之前做过有一点点印象,但还是没能解出来,主要是对结点计算,通过快慢指针找到相同结点来判断链表有环后,没有找到方法来判断环的入口,通过看carl哥题解发现很简单,通过计算得到链表从头开始和从相等结点开始一直往后移动直到相交就是环的入口,总体来说还是很妙的,还好多多加油呀!
/** * 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) { // 思路:利用快慢两个指针,fast和slow,fast一次走2格,slow一次走一格,如果fast遇到了slow说明这个链表有环,然后通过计算推理可以得到相交结点 ListNode* fast = head; ListNode* slow = head; while(fast != nullptr && fast->next != nullptr) { fast = fast->next->next; slow = slow->next; // 相等说明有环,来找环入口 if(fast == slow) { slow = head; while(slow != fast) { slow = slow->next; fast = fast->next; } return fast; } } return nullptr; } };
遇到的困难:
主要是通过快慢指针找到相等结点判断链表有环后难以找到环的入口,通过carl哥题解明白了其中的道理,后面遇到一个能做出来了,到时候在复习复习把。
链表总结:
链表这一章历时2天也完结了,这2天主要是把链表的一些基础操作和一些进阶操作复习了下,链表对于我来说还是有一定难度的,毕竟结点的操作稍有不慎就会溢出报错,要做到足够细致才能完美的AC出一道题,由于之前对链表的增删改查还是比较熟悉,做这些题也没有太大的问题,继续加油把!!!