题目1:24 两两交换链表中的节点
题目链接:24 两两交换链表中的节点
题意
两两交换链表中相邻的节点,返回交换后链表的头节点
虚拟头节点
注意终止条件,考虑节点的奇偶数,根据奇偶数确定终止条件
注意定义中间变量,temp temp1,节点的指向改变时,使用中间变量保存以前指向的节点,以便后续的链表查询操作
完整操作1
代码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* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;//头节点交换时,要知道其前一个节点(dummyhead),所以cur=dummyhead
while(cur->next!=NULL && cur->next->next!=NULL){
ListNode* temp = cur->next;
cur->next = cur->next->next;
ListNode* temp1 = cur->next->next;
cur->next->next = temp;
temp->next = temp1;
cur = cur->next->next;
}
return dummyhead->next;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
完整操作2(先将上述分析的需要定义的中间变量全部提前定义好)
代码
/**
* 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* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* cur = dummyhead;//头节点交换时,要知道其前一个节点(dummyhead),所以cur=dummyhead
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 dummyhead->next;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
题目2:19 删除链表的倒数第N个节点
题目链接:19 删除链表的倒数第N个节点
题意
删除链表中的倒数第n个节点,返回链表的头节点
虚拟头节点
先让fast走n+1步,然后fast和slow再同时移动,这样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* dummyhead = new ListNode(0);
dummyhead->next = head;
ListNode* fast = dummyhead;
ListNode* slow = dummyhead;
n++;
while(n && fast!=NULL){
fast = fast->next;
n--;
}
while(fast!=NULL){
fast = fast->next;
slow = slow->next;
}
ListNode* tmp = slow->next;//定义临时变量,用于释放内存
slow->next = slow->next->next;
delete tmp;
return dummyhead->next;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
题目3:链表相交
题目链接:链表相交
题意
找到两个单链表相交的起始节点;如果没有交点,则返回NULL
注意交点不是数值相等,而是指针相等
步骤
① 链表A定义一个curA指针 curA=headA; 链表B定义一个curB指针 curB=headB
② 链表A的长度lenA 链表B的长度lenB
③ lenA 与 lenB 的差gap
④ 将curA移动gap步 此时curA与curB在相同的位置处(到链表末尾的距离相等)
⑤ curA与curB一同移动 若curA==curB 返回curA 否则,一直移动curA和curB
curA==NULL 代表curA与curB还是不相等,则返回NULL
代码1
/**
* 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* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
while(curA!=NULL){
curA = curA->next;
lenA++;
}
while(curB!=NULL){
curB = curB->next;
lenB++;
}
cout<<lenA<<endl;
cout<<lenB<<endl;
//此时curA curB已经移动到了NULL位置,将curA curB重新指向head处
curA = headA;
curB = headB;
//求解长度差
//首先使得A是最长的链表
if(lenB > lenA){
swap(lenA,lenB);
swap(curA,curB);
}
cout<<lenA<<endl;
cout<<lenB<<endl;
int gap = lenA - lenB;
//将curA移动到与链表B对齐的位置
while(gap){
curA = curA->next;
gap--;
}
//这样curA与curB在同一长度处
while(curA!=NULL && curA!=curB){
curA=curA->next;
curB=curB->next;
}
if(curA!=NULL){
return curA;
}
else{
return NULL;
}
}
};
代码2
/**
* 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* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
while(curA!=NULL){
curA = curA->next;
lenA++;
}
while(curB!=NULL){
curB = curB->next;
lenB++;
}
//此时curA curB已经移动到了NULL位置,将curA curB重新指向head处
curA = headA;
curB = headB;
//求解长度差
//首先使得A是最长的链表
if(lenB > lenA){
swap(lenA,lenB);
swap(curA,curB);
}
int gap = lenA - lenB;
//将curA移动到与链表B对齐的位置
while(gap){
curA = curA->next;
gap--;
}
//这样curA与curB在同一长度处
while(curA!=NULL){
if(curA==curB){
return curA;
}
curA=curA->next;
curB=curB->next;
}
return NULL;
}
};
- 时间复杂度:O(n + m)
- 空间复杂度:O(1)
题目4:142 环形链表Ⅱ
题目链接:142 环形链表Ⅱ
题意
判断链表有无环,有环的话则返回开始入环的第一个节点;无环则返回null
主要分两个步骤:
①判断有环 无环
使用fast slow两个指针,fast每次走两个节点,slow每次走1个节点,若有环,则fast,slow一定会在环内相遇 因为相对于slow,fast是每次走1个节点靠近slow,所以一定会和slow重合
②有环的话,返回入环的第一个节点;无环的话,返回null
fast,slow相遇时,fast走过的节点数为x+y+n(y+z),slow走过的节点数为x+y
fast走过的节点数=2*slow走过的节点数 n>=1
伪代码
代码
/**
* 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* index1 = fast;
ListNode* index2 = head;
while(index1!=index2){
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
return NULL;
}
};
- 时间复杂度: O(n),快慢指针相遇前,慢指针走的次数小于链表长度(没走1圈fast和slow就相遇了),快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n
- 空间复杂度: O(1)