1.24两两交换链表中的节点
思路:首先来说的话,找到对应的边界条件,不存在或者只有一个的时候,直接返回即可。第二种情况就是普通情况下分为两种情况,第一种是单数,第二种是双数,在这种情况下,单数或者双数要满足的就是对应的一个当前节点非空是单数情况,next节点是双数情况。
知识点:虚拟头节点、链表知识、画图
关键点:
·pre节点:当前节点的前面的节点(不参与交换)
·cur节点:当前节点
·next节点:cur的next节点(因为这样保证)
·链表交换的顺序
/**
* 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) {
if(head==nullptr||head->next == nullptr){//两种对应的特殊情况
return head;
}
ListNode* dummyHead = new ListNode(0);//虚拟头结点
dummyHead->next = head;
ListNode* cur = head;
ListNode* next = head->next;
ListNode* pre = dummyHead;
while(cur!=nullptr&&cur->next!=nullptr){//当前节点或者下一个节点为空,代表退出
next = cur->next;
cur->next = next->next;
next->next = cur;
pre->next = next;
pre = cur;
cur = cur->next;
}
cur = dummyHead->next;
delete dummyHead;
return cur;
}
};
2.19删除链表的倒数第N个节点
思路:快慢指针,让快指针和慢指针之间的距离差为n+1,这样可以保证快指针指到最后的时候,慢指针指向要删除节点的前一个位置,这样可以更好的进行删除节点的操作。
知识点:快慢指针、虚拟头节点
注意事项:
·虚拟头节点保证如果我们要是删除的是头结点的时候,还能找到对应的一个新的头结点,统一操作。
·快慢指针,快指针指向head,然后移动n步,慢指针指向虚拟头节点,这样此时两个节点之间的距离是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;
ListNode* cur = head;
ListNode* tmp = dummyHead;
//我们前面对应的指向head,保证的是对应的一个多移动一位,使其在后面的tmp指向要删除的前面的那个节点
while(n--){
cur = cur->next;
}
while(cur!=nullptr){
cur = cur->next;
tmp = tmp->next;
}
ListNode* tmp2 = tmp->next;
tmp->next = tmp2->next;
delete tmp2;
cur = dummyHead->next;
delete dummyHead;
return cur;
}
};
3.面试题02.07链表相交
思路:两链表相交,需要注意的是这个题目里面规定每个链表都不是环形链表,如果是环形链表的话,就需要考虑一些其他的问题,比如说此时我们先需要考虑这个是不是环形链表,另外一个是不是环形链表,如果是环形链表的话,此时长度会有多少。具体怎么判断是否是环形链表可以看下一题。
知识点:链表、双指针
注意事项:
·节点相等是都相等而不是值相等,要用节点判断
·使用快慢指针,通过两个链表长度的差值确定移动的距离,移动到同一个位置,然后同时移动判断是否相等。
/**
* 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) {
int lenA = 0,lenB = 0;
ListNode* curA = headA;
ListNode* curB = headB;
while(curA!=NULL){
lenA++;
curA = curA->next;
}
while(curB != NULL){
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
ListNode* fast = NULL;
ListNode* slow = NULL;
int diff = 0;
if(lenA>lenB){
diff = lenA-lenB;
fast = curB;
slow = curA;
}else{
diff = lenB - lenA;
fast = curA;
slow = curB;
}
while(diff--){
slow = slow->next;
}
while(fast!=NULL){
if(fast==slow){
return fast;
}
fast = fast->next;
slow = slow->next;
}
return NULL;
}
};
4.142环形链表
思路:纯数学的知识,先通过快慢指针的双指针方法找到相遇的结点,然后再将一个指针指向头结点,相同的速度移动即可完成相应的找到结点的位置
知识点:双指针、数学
/**
* 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){
break;
}
}
if(fast==NULL||fast->next == NULL){
return NULL;
}
slow = head;
while(fast!=NULL){
if(fast == slow){
return fast;
}
fast = fast->next;
slow = slow->next;
}
return NULL;
}
};
5.小总结
链表相关的知识
·链表的构造和查找删除
·链表删除的时候我们需要将指针指向前一个结点
·链表交换的顺序不能乱
双指针
·快慢指针:主要包括①两个指针以不同的速度进行遍历②快指针遍历,慢指针当满足条件时更新。③两个指针相差一个固定的距离。
·左右指针:一个指针指向left,一个指针指向right,根据题目的条件进行更新。