24. 两两交换链表中的节点
题目链接24. 两两交换链表中的节点
这道题还是用虚拟头结点的方式简单一点
首先我们判断终止条件,如果是偶数,则下一个是空指针停止,如果是奇数,则下一个的下一个指针为空停止
while(cur->next &&cur->next->next )
要注意cur->next要现在前面,二者不可以调换,因为&&优先级从左往右,会在偶数时造成空指针报错
然后注意交换顺序,先保存节点1,3的地址
我们dummyhead->next = head; cur=dummyhead;
因为只有知道要交换的两个节点的前一个节点,我们才能对要交换的两个节点进行操作,这就是链表的特点
红色为第一步,让dummyhead指向节点2
绿色为第二步,让节点2指向节点1
黄色为第三步,让节点1指向节点3
至此,这一串就交换好了,链表为dummyhead->2->1->3
/**
* 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) {
//虚拟头节点指向head
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
//auto == ListNode*
auto cur = dummyhead;
while(cur->next &&cur->next->next ){
//保存1节点地址
auto temp1 = cur->next;
//保存3节点地址
auto temp2 = cur->next->next->next;
//交换
cur->next = cur->next->next;
cur->next->next = temp1;
temp1->next =temp2;
cur = cur->next->next;
}
return dummyhead->next;
}
};
19.删除链表的倒数第N个节点
题目链接如下
这道题使用两个指针可以很方便的做出来,首先,我们要删除倒数第n个节点,我们必须操作倒数第n+1个节点
我们先创建一个虚拟头节点,让两个指针都等于虚拟头节点,快指针先移动n+1次,之后快慢指针一起移动,直到快指针为空的位置,这时慢指针的位置就位于倒数n+1的位置了
完整代码如下:
/**
* 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* dummyhead = new ListNode(0);
dummyhead->next = head;
//两个指针
auto fast = dummyhead;
auto slow = dummyhead;
n += 1;
//判断特殊情况
if(!head | !head -> next) return NULL;
//先动快指针
while(n--){
fast = fast->next;
}
//一起移动
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
//删除操作
slow->next = slow->next->next;
//有可能删除的是原头节点,所以我们返回的应该是虚拟头节点的next
return dummyhead->next;
}
};
02.07. 链表相交
题目链接面试题 02.07. 链表相交
这道题也是双指针解法
用两个指针分别在两个链表开头开始走,如果一个指针走到null了,也就是走到头了,就再从另一个链表的开头开始走,这样,两个指针最后相遇的地方就会是第一个公共交点。
画的不太好,语言描述太乏力了
具体实现到代码如下:p,q就是两个指针
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
auto p=headA,q=headB;
while(p!=q){
if(p)p=p->next;
else p=headB;
if(q)q=q->next;
else q=headA;
}
return q;
}
};
142.环形链表II
题目链接如下:
快指针每次走两步,慢指针每次走一步,如果它们相遇了,则证明是环形
核心是通过数学推出,从两指针相遇节点出发和从头节点出发,到环形入口节点的距离相同
我的理解是,进入环的距离假设为X,快指针相对与慢指针的相对速度为1,所以它们相遇时的追赶距离就是Z这段路上快指针对慢指针的相对位移
/**
* 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) {
auto fast = head;
auto slow = head;
while(fast != NULL && fast->next != NULL){
/fast每次走两步 slow每次走一步
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
//从相遇点开始
auto tmp1 = head;
auto tmp2 = fast;
while(tmp1 != tmp2){
tmp1 = tmp1->next;
tmp2 = tmp2->next;
}
//相交处既是环形入口
return tmp1;
}
}
//不是环形则返回空
return NULL;
}
};