想法:链表题再练习
想法:两两交换,移动搜索指针进行,需要注意边界判断
阅读后想法:虚拟节点很方便,由于我们在交换的过程中,会丢失对head的指向,通过一个虚拟节点来避免这个问题的发生
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* newHead = new ListNode(-1);
newHead->next = head;
ListNode* cur = newHead;
while(cur->next!=nullptr && cur->next->next!=nullptr) {
ListNode* next = cur->next;
cur->next = cur->next->next;
next->next = cur->next->next;
cur->next->next = next;
cur = next;
}
return newHead->next;
}
};
想法:有两个做法,一种遍历链表,计算出链表长度,进行加减运算;一种,先反转链表,删除后,再反转;突然又有个想法,用双指针,fast指针先走n步,再跟slow指针同时走,当fast走到空的时候,slow就是对应的
阅读后想法:同样为了避免头节点丢失,使用虚拟头节点
思路:找到需要删除节点的前一节点,通过两个指针一起移动来定位到
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* newHead = new ListNode(-1);
newHead->next = head;
ListNode* fast = newHead;
ListNode* slow = newHead;
while(n--) {
fast = fast->next;
}
while(fast->next!=nullptr) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return newHead->next;
}
};
想法:一种是用set数据结构,保存节点,判断是否相遇;但是这题是面试题,需要考虑空间复杂度,因此可以通过遍历两个链表,求出长度差值,长链表先移动差值,再同时移动
a. 如果笔试出现 (时间复杂度优先)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode*> myset;
ListNode* cur = headA;
while(cur!=NULL) {
myset.insert(cur);
cur = cur->next;
}
cur = headB;
while(cur!=NULL) {
if(myset.find(cur)!=myset.end()) {
break;
}
cur = cur->next;
}
return cur;
}
};
b. 如果面试出现 (考虑空间复杂度)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* cur = headA;
int size = 0;
while(cur!=NULL) {
size++;
cur = cur->next;
}
cur = headB;
while(cur!=NULL) {
size--;
cur = cur->next;
}
ListNode* fast = size>0?headA:headB;
ListNode* slow = fast==headA?headB:headA;
size = abs(size);
while(size--) {
fast = fast->next;
}
while(fast!=NULL) {
if(fast==slow) {
return fast;
}
fast = fast->next;
slow = slow->next;
}
return NULL;
}
};
想法:两种想法,一种是通过set,一种是通过两个指针,一个走一步,一个走两步(规律),由于需要返回入环节点,因此当相遇以后,快指针回到头节点初,再次相遇则成
a. 笔试题
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
unordered_set<ListNode*> myset;
ListNode* cur = head;
while(cur!=NULL) {
if(myset.find(cur)!=myset.end()) {
return cur;
}else {
myset.insert(cur);
cur = cur->next;
}
}
return NULL;
}
};
b. 面试题
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(true) {
if(fast==NULL || fast->next==NULL) {
return NULL;
}
fast = fast->next->next;
slow = slow->next;
if(fast==slow) {
break;
}
}
fast = head;
while(fast!=slow) {
fast = fast->next;
slow = slow->next;
}
return slow;
}
};
总结:
链表题目主要是双指针,虚拟头节点的应用,或者说创建多个节点的指向,在这个过程中需要注意关于指针丢失,提前存好位置等