LeetCode24.两两交换链表中的节点 题目链接:24.两两交换链表中的节点
题目要点与解题思路 这题考察的是模拟,因为在操作的时候一些链会断开,所以一定要想清楚如何暂存节点,并且本题适合用 dummy 处理,因为 head 没有人指着,和后面的逻辑有所不同
我的解法是步骤 3-步骤 2-步骤 1,代码如下:
实现代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : ListNode* swapPairs (ListNode* head) { ListNode* dummy = new ListNode (-1 , head); ListNode* cur = dummy; ListNode* tmp; while (cur && cur->next && cur->next->next) { tmp = cur->next->next; cur->next->next = cur->next->next->next; tmp->next = cur->next; cur->next = tmp; cur = cur->next->next; } head = dummy->next; delete dummy; return head; } };
遇到的问题与总结 模拟起来比较麻烦,注意保存被断开的节点
LeetCode19.删除链表的倒数第 N 个结点 题目链接:19.删除链表的倒数第 N 个结点
题目要点与解题思路 链表不可以随机访问,所以看起来倒数第几个有点难以定位,第一次做会想是不是要先遍历一遍链表,得到长度,然后再遍历(长度- n) 下来确定删除的位置
其实可以用双指针来解决(快慢指针),让快指针先跑,等快指针跑到最后一个节点的时候,慢节点就正好在要删除的节点的前一个节点上
实现代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : ListNode* removeNthFromEnd (ListNode* head, int n) { ListNode* dummy = new ListNode (-1 , head); ListNode *fast = dummy, *slow = dummy; while (n--) { fast = fast->next; } while (fast->next) { fast = fast->next; slow = slow->next; } slow->next = slow->next->next; head = dummy->next; delete dummy; return head; } };
遇到的问题与总结 想到快慢指针就行,看到“链表倒数第几个”这样的内容就可以考虑快慢指针了
LeetCode 面试题 02.07.链表相交 题目链接:面试题 02.07.链表相交
题目要点与解题思路 只能说这道题实在是太巧了,这哪是算法题,这妥妥的脑筋急转弯!!
先讲常规解法,非常简单,先遍历一遍链表 A,得到长度,然后遍历一遍链表 B,得到长度,然后让长的链表先走(长度差),然后两个链表一起走,直到相遇
但是其实有一个很巧妙的解法,来自 leetcode-cn 的题解:面试题 02.07. 链表相交(双指针,清晰图解)
指针 A,B 分别从链表 A 和 B 的头节点出发,走到链表的尾部,然后指向另一个链表的头节点,继续走到尾部,如果在公共节点相遇,则他们走的路径是相同的,所以相遇的节点就是交点,原理证明如下:
A 走到尾部再去 B 的头部开始走,总长度为
B 走到尾部再去 A 的头部开始走,总长度为
所以两者走的路一样,会重合,分为如下两种:
如果有交点,即 c>0,两个指针同时指向公共交点
如果没有交点,即 c=0,两个指针同时指向 NULL
实现代码 常规解法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { class Solution { public : ListNode *getIntersectionNode (ListNode *headA, ListNode *headB) { ListNode* curA = headA; ListNode* curB = headB; int lenA = 0 , lenB = 0 ; while (curA != NULL ) { lenA++; curA = curA->next; } while (curB != NULL ) { lenB++; curB = curB->next; } curA = headA; curB = headB; if (lenB > lenA) { swap (lenA, lenB); swap (curA, curB); } int gap = lenA - lenB; while (gap--) { curA = curA->next; } while (curA != NULL ) { if (curA == curB) { return curA; } curA = curA->next; curB = curB->next; } return NULL ; } }; };
这个是卡哥的解法,比较常规,时间复杂度 ,空间复杂度
巧妙解法 1 2 3 4 5 6 7 8 9 10 11 class Solution {public : ListNode *getIntersectionNode (ListNode *headA, ListNode *headB) { ListNode *a = headA, *b = headB; while ( a != b) { a = a != nullptr ? a->next : headB; b = b != nullptr ? b->next : headA; } return a; } };
遇到的问题与总结 这道题的巧妙解法是真的挺有意思的,感觉是一个脑筋急转弯的题目,常规解法也很简单,面试遇到肯定还是追求先写常规解法
另外我在二刷的时候一直遇到一个 bug,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution {public : ListNode *getIntersectionNode (ListNode *headA, ListNode *headB) { ListNode *a = headA, *b = headB; while (a != b) { a = a->next; if (a == NULL ) a = headB; b = b->next; if (b == NULL ) b = headA; } return a; } };
这样相当于我提前把 a 跳转到了 headB,会导致两者遇不上(正确的代码会在 null 上停留一轮),考虑如下情景:链表没有交点
交换过后,两者应该同时到了 null,但是一达到 null 就跳转了,导致两者变成了 headB 和 headA,会一直遇不到导致死循环
LeetCode142.环形链表 II 题目链接:142.环形链表 II
一刷被震撼到,二刷还是没一下子想出来,我先放一下
参考资料 代码随想录-两两交换链表中的节点 面试题 02.07. 链表相交(双指针,清晰图解) 代码随想录-链表相交 代码随想录-环形链表 II