一、LeetCode24 两两交换链表中的节点
两两交换链表中的节点。给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
两两交换,最后一个节点如果没人了可以不交换的(原来是这样)
其实这是一个模拟题,推荐使用虚拟头结点方式进行,因为你必须知道这个节点的前一个节点。
自己写一遍其实能发现问题了:统一用dummyhead操作,不然容易晕!
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode*dummy_head=new ListNode(0);
dummy_head->next=head;
ListNode*cur=dummy_head;
while(cur->next!=NULL&&cur->next->next!=NULL){//这一步不能写反哦,不然空指针异常了
ListNode*temp=cur->next;
ListNode*temp1=cur->next->next->next;
cur->next=cur->next->next;
cur->next->next=temp;
temp->next=temp1;
cur=cur->next->next;
}
return dummy_head->next;
}
};
链表指针指向题还是画图好理解,看不懂了就自己画个图。
二、LeetCode19删除链表倒数第N个节点。
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
双指针典中典!fast先走n步,然后fast和slow同时移动,fast走到末尾,删除slow对应指针。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode*dummy_head=new ListNode(0);
dummy_head->next=head;
ListNode*fast=dummy_head;
ListNode*slow=dummy_head;
while(n--&&fast!=NULL){
fast=fast->next;
}
fast=fast->next;
while(fast!=NULL){
fast=fast->next;
slow=slow->next;
}
slow->next=slow->next->next;
return dummy_head->next;
}
};
一遍过,轻轻松松拿下!只是需要注意,fast指针先走n+1步,然后二者同时移动,因为删除操作要操作上一个指针嘛!
当然C++删除元素的逻辑,还是要靠delete。
三、LeetCode142环形链表
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
判断有环:双指针法真的好用!fast指针一次走两步,slow指针一次走一步,fast指针先进入环,其后fast和slow相互追赶,二者相对速度为1,在环中肯定能相遇。遇上了就说明有环。
如何找到环的入口?
这里面的数学逻辑就深奥了,图片我不放出来,可以看上面连接的代码随想录,卡哥的动画还是很直观的。
fast指针路程:x+y+n(y+z); slow指针路程:x+y;(为什么slow指针不是好几圈详看代码随想录)
二者速度差二倍关系,所以有:x+y+n(y+z)=2(x+y);
所以x=ny+nz-y=(n-1)y+nz=(n-1)(y+z)+z;
当n=1时,公式化简为x=z;也就是fast指针走了一圈就遇到了slow。
所以我们在相遇点再定义一个指针,头节点定义一个指针,二者同时移动,每次一个单位,相遇 点就是环的入口。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};
四、LeetCode160链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
异曲同工!和删除倒数第n个节点异曲同工之妙!双指针已经写了不少题了,到时候总结一下。
相交节点不是值相同,而是指针相同。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
目前看来是一道注水的模拟题....不过话说回来卡哥的函数名字真的好长啊。