P24 两两交换链表中的节点
思路:
定义中间变量进行交换就好
/**
* 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) {
ListNode* dyummhead = new ListNode(0);
dyummhead->next = head;
ListNode* cur = dyummhead;
while(cur->next !=nullptr &&cur->next->next !=nullptr){
ListNode* tmp =cur->next;
ListNode* tmp1 = cur->next->next->next;//
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp1;
cur = cur->next->next;
}
return dyummhead->next;
}
};
P19 删除链表的倒数第N个节点
思路:
定义fast指针和slow指针,初始值为虚拟头结点, fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),fast和slow同时移动,直到fast指向末尾,删除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) {
ListNode* dyummhead = new ListNode(0);
dyummhead->next = head;
ListNode* fast = dyummhead;//
ListNode* slow = dyummhead;//
while(n && fast !=NULL){
fast = fast->next;
n--;
}
fast = fast->next;//
while(fast !=NULL){
fast=fast->next;
slow=slow->next;
}
slow->next = slow->next->next;
return dyummhead->next;
}
};
面试题02.07 链表相交
思路:
注意点:指针相同不是值相同,而是指针的地址相同。
两个链表相交,那么从交点开始两个链表后面的部分都相同。那么我们可以把两个链表的尾部对齐,将长链表的指针移动到较短指针开始的位置
然后再遍历链表A和链表B,找到相等的节点即可
代码:
/**
* 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 *answer = NULL;
int lenA = 0,lenB = 0;
ListNode *curA = headA;
ListNode *curB = headB;
while(curA !=NULL){
lenA ++;
curA = curA->next;
}
while(curB !=NULL){
lenB++;
curB = curB->next;
}
curA =headA;
curB = headB;
int gap;
if(lenA>lenB){
gap = lenA - lenB;
while(gap){
curA = curA->next;
gap--;
}
}else if(lenA <lenB){
gap = lenB - lenA;
while(gap){
curB = curB->next;
gap--;
}
}else{
gap = 0;
}
while(curA!=NULL &&curB !=NULL){
if(curA == curB){
answer = curA;
break;
}
curA = curA->next;
curB = curB->next;
}
return answer;
}
};
P142 环形链表||
思路:
1.如何判断链表是否有环:
利用双指针,定一个一快慢指针,其中快指针一次移动两个节点,慢指针一次移动一个节点,因为快指针的移动速度是慢指针移动速度的两倍,那么在经过环的时候,在慢指针在环内转了一圈之前,快慢指针必然会相遇一次。若快慢指针相遇,则可以证明该链表存在环。
2.如何找到该环的入口:
在相遇节点和头节点处各定义一个指针,指针相遇的地方必然是该环的路口。原因:
假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。 如图所示:
那么相遇时: 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指针。根据公式,则环的入口x必然等于转的圈数-1加上z,那么可以定义一个指针meet在相遇节点上,定义一个catcher节点在头结点上,然后让两个指针同时出发,他们相遇的节点就是环的入口。
代码:
/**
* 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) {
ListNode *fast = head;
ListNode *slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
ListNode *meet = fast;
ListNode *catcher = head;
while(meet != catcher){
meet = meet->next;
catcher = catcher->next;
}
return catcher;
break;
}
}
return NULL;
}
};