链表part02
1.两两交换链表中的节点24
主要是要厘清交换的顺序,主要有三个步骤,由于其中的交换和前后关系非常复杂,会需要使用到两个临时存储节点值的变量,在这个过程中容易迷糊。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur->next != nullptr && cur->next->next !=nullptr){
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp1;
cur = cur->next->next;
}
ListNode* result = dummyHead->next;
delete dummyHead;
return result;
}
};
2.删除链表的倒数第N个节点17
可以理解为像滑动窗口一样,将n个节点这个窗口整个从最前端移动到末尾,那么后面那个指针指向的位置就是需要删除的位置的前一个。这种思路的原因应该是链表的数据结构特殊,不方便从尾巴往前进行遍历,所以可以采用这种移动窗口的方式。
还需要注意,一定是最后的后面那个指针指向需要删除的前一个位置。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
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 dummyHead->next;
}
};
感觉这种利用快慢指针滑动窗口的方式非常神奇,值得反复琢磨和学习,在一些情形下会有妙用。
3.链表相交面试02.07.
首先因为链表是有前后顺序的存储结构,所以有相交的节点一定是后半部分,这时候需要将两个链表后边的部分对齐,然后从对齐位置的开头开始找,遍历就能够找到相交的位置。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while(curA != NULL){
lenA++;
curA = curA->next;
}// 求链表A的长度
while(curB!=NULL){
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
if(lenB>lenA){
swap(lenA,lenB);
swap(curA,curB);
}
int gap = lenA-lenB;
while (gap--){
curA = curA->next;
}
while (curA!=NULL){
if(curA == curB){
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
主要是要认识到后端对齐然后从对齐的开头开始往后遍历的点,明白这个点就可以大致得到结果了。
4.环形链表Ⅱ142
首先要想明白怎么判断链表中间是否有环,跟指针有关可以想到快慢指针的使用,快指针往前走两步,慢指针往前走一步,最后两个指针一定会在环里相遇,如果没有相遇就说明没有环存在。
这块其实还是挺好理解的,相当于两者有一个速度差。
然后就需要找到环的入口,这部分需要结合讲解理解一下,跟推导相遇问题很像,把每个过程的未知量设出来然后计算一下,能够的出来从相遇的点出发一个指针,从开头出发一个指针,这两个指针相遇的位置就是环的入口。
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;
if(slow == fast){
ListNode* index1 = fast;
ListNode* index2 = head;
while(index1!=index2){
index1 = index1->next;
index2 = index2->next;
}
return index2;
}
}
return NULL;
}
};
总结
链表是一个相对来说比较复杂的数据结构,需要仔细分析前后关系,在处理其中节点的时候也要注意操作的出发点。在具体设计代码的时候需要仔细盘算一下结构。感觉这部分有时间还要回顾一下。