链表总结:
1.一般都是链表的插入操作和删除操作的变形只要掌握这两个方法就可以掌握很多链表的题目。
其实变相的就是链表的插入操作 。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;
while(cur->next != NULL && cur->next->next != NULL){
ListNode* newhead = cur->next;
cur->next = cur->next->next;
newhead->next = cur->next->next;
cur->next->next = newhead;
cur = cur->next->next;
}
return dummyhead ->next;
}
};
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
这道题用了双指针 (快慢指针)通过快慢指针的位置来找到需要删除的位置比如倒数第2个位置怎么找到 让快指针比慢指针多走2格 所以慢指针的后一个位置就是需要删除的位置。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* slow = dummyhead;
ListNode* fast = dummyhead;
while(n--){
if(fast != NULL && fast->next !=NULL){
fast = fast->next;
}
}
while(fast != NULL && fast->next !=NULL){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummyhead->next;
}
};
面试题 02.07. 链表相交 - 力扣(LeetCode)
写这道题的时候先明确一点 链表的定义是什么他们是如何存储的
然后再看这道题,先让他们尾部对齐,这样才能找到像交的点 ,然后遇见相等的点的时候直接输出就行了 首先先循环看看哪个长 然后把长度弄成一样。
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(lenA>lenB){
int gap = lenA -lenB;
while(gap--){
curA = curA->next;
}
}
else{
int gap = lenB -lenA;
while(gap--){
curB = curB->next;
}
}
while(curA != curB ){
curA = curA->next;
curB = curB->next;
}
return curA;
}
};
这道题可以有两问 第一问就是 如何判定是环呢?
用双指针法 定一个快指针和一个慢指针 快指针走2格 慢的走一格 ,如果有环他们就会相遇,
为什么会相遇呢 快指针比慢指针多走一格肯定会相遇,如果多走两个那就不一定了。
如何找到环的入口呢,
这就类似于套圈快指针跑两圈 慢指针跑一圈,所以慢指针没跑一圈就被抓住了,
那么相遇时: slow指针走过的节点数为: x + y
, fast指针走过的节点数:x + y + n (y + z)
,n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。
因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:
(x + y) * 2 = x + y + n (y + z)
两边消掉一个(x+y): x + y = n (y + z)
因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。
所以要求x ,将x单独放在左面:x = n (y + z) - y
,
再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z
注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。(因为快指针要追慢指针肯定跑了一圈了 如果想不通就想想跑步是如何追上别人的 肯定是比他至少多一圈才能追上 )
这个公式说明什么呢?
先拿n为1的情况来举例,意味着fast指针在环形里转了一圈之后,就遇到了 slow指针了。
当 n为1的时候,公式就化解为 x = z
,
这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。
让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast ==slow){
ListNode* index = head;
ListNode* index1 = fast;
while(index != index1){
index = index->next;
index1 = index1->next;
}
return index1;
}
}
return NULL;
}
};