24. 两两交换链表中的节点
- 题目链接:24. 两两交换链表中的节点
- 独立思路:❌ 没想出来,只想得出交换结点值的
- 解法1(递归):我悟了!重点是取一对相邻结点
A->B
为研究对象,假设后续的pairs全部都已经交换完成,且返回的是已经完成交换的链表部分的新头结点newHead。则本对结点交换后的新头结点newHead = B
,A->next = swapPairs(B->next)
,最后将newHead->next = head
即可。 - 时间复杂度:O(n)
- 空间复杂度:O(n)
class Solution{
public:
ListNode* swapPairs(ListNode* head){
if(!head || !head->next) //如果链表为空或者只有一个结点,则没什么好交换的
return head;
ListNode* newHead = head->next;
head->next = swapPairs(newHead->next); //后面链表的开头结点是原来的B->next
newHead->next = head;
return newHead;
}
};
- 解法2(迭代):重点是设置一个dummyHead,以及一个cur指针来从dummy开始遍历整个链表,需要进行循环处理的是紧接temp之后的两个结点node1和node2,直到cur指针后面没有结点或者只有1个结点时退出循环。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
//解法2:迭代
class Solution{
public:
ListNode* swapPairs(ListNode* head){
if(!head)
return head;
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* cur = dummy;
while(cur->next && cur->next->next){
ListNode* node1 = cur->next;
ListNode* node2 = node1->next;
cur->next = node2;
node1->next = node2->next;
node2->next = node1;
cur = node1;
}
ListNode* newHead = dummy->next;
delete dummy;
return newHead;
}
};
19.删除链表的倒数第N个节点
- 题目链接:19.删除链表的倒数第N个节点
- 独立思路:双指针法定位倒数第N个结点
- 时间复杂度:O(n)
- 空间复杂度:O(1)
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *left = head;
ListNode *right = head;
ListNode *pre;
while(n != 0 && right != NULL){
right = right->next;
n--;
}
if(n != 0){ //n还没有减到0时,right就已经为NULL,说明链表根本不够长
return NULL;
}
else if(right == NULL){ //n=0且right已经到了NULL,说明要删除的是第一个结点
return head->next;
}
else{ //n=0且right还没到NULL时
while(right != NULL){
pre = left;
left = left->next;
right = right->next;
} //结束循环时,left指向倒数第n个结点,pre指向其前一个结点
pre->next = left->next;
return head;
}
}
}; //还可以添加个dummyHead更简单点
面试题02.07. 链表相交
- 题目链接:面试题02.07. 链表相交
- 独立思路:计算两个链表的长度,更长的那个链表重新设置开始结点,让两个指针cur1和cur2分别从两个链表的长度相等的地方开始遍历,
cur1 == cur2
时即为相交处 - 时间复杂度:O(m+n)
- 空间复杂度:O(1)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int len1 = 0; int len2 = 0;
ListNode* cur1 = headA;
ListNode* cur2 = headB;
while(cur1){
len1++;
cur1 = cur1->next;
}
while(cur2){
len2++;
cur2 = cur2->next;
}//计算A、B链表的长度
cur1 = headA;
cur2 = headB; //两个遍历指针归位
if(len1 == len2){ //两链表等长
while(cur1){
if(cur1 == cur2)
return cur1;
cur1 = cur1->next;
cur2 = cur2->next;
}
}else if(len1 < len2){ //链表B更长
while(len2 != len1){
cur2 = cur2->next;
len2--;
}//强行让A、B同长度开始遍历
while(cur1){
if(cur1 == cur2)
return cur1;
cur1 = cur1->next;
cur2 = cur2->next;
}
}else{ //链表A更长
while(len1 != len2){
cur1 = cur1->next;
len1--;
}//强行让A、B同长度开始遍历
while(cur1){
if(cur1 == cur2)
return cur1;
cur1 = cur1->next;
cur2 = cur2->next;
}
}
return NULL;
}
};
- 另解1(哈希表):遍历A链表,将A表中的结点全部存入set表中(set可以用find函数找元素),再遍历B链表,判断当前遍历到的B表结点是否存在于set表中,(若存在则后续链表结点都存在),即直接返回该结点
- 时间复杂度:O(m+n)
- 空间复杂度:O(m)
//解法2:哈希表
class Solution{
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB){
unordered_set<ListNode*> visited;
ListNode* cur1 = headA;
ListNode* cur2 = headB;
while(cur1){
visited.insert(cur1);
cur1 = cur1->next;
}
while(cur2){
if(visited.find(cur2) != visited.end()){
return cur2;
}
cur2 = cur2->next;
}
return NULL;
}
};
- 另解2(循环双指针):假设链表A和B公共部分的长度为x,非公共部分的长度分别为a和b。cur1和cur2分别从头开始遍历两个链表,当cur1≠cur2,且遍历到了尾部,指针走到另一个链表的开头继续走,直到cur1=cur2。原理就是a+c+b = b+c+a。
- 问题(已解决):while循环内的两个判断,只能判断cur是否为空而不能判断cur->next是否为空!因为在两个链表不相交的情况下,如果是判断cur->next为空时就跳转到另一个链表的开头,那么两个cur永远不可能同时为NULL,会陷入死循环。
- 时间复杂度:O(m+n)
- 空间复杂度:O(1)
//解法3: 循环双指针
class Solution{
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB){
if(!headA || !headB)
return NULL;
ListNode* cur1 = headA;
ListNode* cur2 = headB;
while(cur1 != cur2){
cur1 = cur1? cur1->next: headB; //只能判断cur而不能判断cur->next
cur2 = cur2? cur2->next: headA;
}
return cur1;
}
};
142.环形链表II
- 题目链接:142.环形链表II
- 独立思路:如果有环,快慢指针一定会相遇(好像做过一模一样的题,但是想不起来后面的了)
- 官方题解:快慢指针两轮运动,设链表从head到环起点部分长度为a,环的部分长度为b。
① slow走一步,fast走两步,直到fast==slow
,此时f = 2s且f = s+nb。得f = 2nb s = nb
② 将fast又重新置为head,这一轮slow与fast同步走了a步,相遇的位置即为环的起点位置(fast走到入口,slow则总共走了nb+a,也走到了入口)
- 时间复杂度:O(n)
- 空间复杂度:O(1)
//想法:如果有环,快慢指针一定会相遇
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(!head || !head->next) //0或1个结点无法构成环
return NULL;
ListNode* slow = head;
ListNode* fast = head;
while(fast && fast->next){
slow = slow->next; //第一轮,slow慢走,fast快走
fast = fast->next->next;
if(fast == slow){
fast = head; //第二轮出发,slow、fast同速走
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}
};