两两交换链表中的节点
这是一个什么问题?
想象一个链表的图片,由箭头和节点组成一串,只是把节点两两交换,节点不动。
思路
逻辑思路
分三步,先把虚拟头结点指向第二个节点,再把第二个节点指向第一个节点,相当于完成了两个节点的调换,然后还需要把第一个节点指向第三个节点,之后cur变为1节点,重复上面的操作直到只剩一个数或者没有剩下的数,两种情况对应着奇数个节点和偶数个节点。
代码思路
定义一个虚拟头结点,设定为cur,一个while循环,停止条件是cur节点的next指向空指针或者cur->next->next为空指针,这对应着奇数和偶数两种情况。操作的过程需要定义一些temp因为只要让一个节点指向另一个原本他没指向的地方的时候,他原本指向的地方就可能会找不到,因为单向链表是单向串联的,一旦断开,紧邻的后面的节点就找不到了。
代码
/**
* 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) return {};
else {
if (head->next == nullptr) return head;
}
ListNode *fake = new ListNode(-1);
fake->next = head;
ListNode *cur = fake;
ListNode *temp1;
ListNode *temp2;
while (cur->next != nullptr && cur->next->next != nullptr) {
temp1 = cur->next;
temp2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = temp1;
temp1->next = temp2;
cur = temp1;
}
return fake->next;
}
};
//赋值之前使用temp记录
删除链表的倒数第n个节点
思路
定义个虚拟头节点,fast先走n,再多走一步,确保等下slow能到指定点的前面,方便删除操作,然后fastslow一起走,直到fast走到最后,然后执行删除操作就好。记得释放节点,定义虚拟头结点是为了统一操作,不用特殊处理特殊情况。
代码
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 = fast->next;
}
fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
// ListNode *tmp = slow->next; C++释放内存的逻辑
// slow->next = tmp->next;
// delete nth;
return dummyHead->next;
}
};
链表相交
这是一个什么问题呢?
找到两个链表他们没有合二为一的点
思路
分别遍历两个链表,找到他们的长度,根据他们的长度重新定下他们的初始头结点,然后一起往后走,当发现他们一样的时候,那就是有合二为一的点,返回这个点
代码
/**
* 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 i = 0;
int j = 0;
int k;
ListNode *curA = headA;
ListNode *curB = headB;
if (curA == NULL || curB == NULL) return NULL;
if (headA == headB) return headA;
while (curA != NULL) {
curA = curA->next;
i++;
}
while (curB != NULL) {
curB = curB->next;
j++;
}
curA = headA;
curB = headB;
if (i > j) {
k = i - j;
while (k--) {
curA = curA->next;
}
}
if (i < j) {
k = j - i;
while (k--) {
curB = curB->next;
}
}
while (curA != curB) {
if (curA == NULL) return NULL;
curA = curA->next;
curB = curB->next;
}
return curA;
}
};
环形链表
这是一个什么问题?
看链表里面有没有环
思路
一个快指针,一个慢指针,快指针每次移动2个节点,慢指针每次移动1个节点,要是有环的话,他们一定会在环中相遇,要是没有他们就会走向null,找到环的起始点方法是,在快慢指针相遇的点定义一个index1,在头定义一个index2.让他们开始走,当他们接触的时候,他们接触的节点就是环的节点。
代码
/**
* 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) {
if (head == NULL) return NULL;
ListNode *fast = head;
ListNode *slow = head;
bool flag = 0;
ListNode *index1;
ListNode *index2;
while (fast->next != NULL && fast->next->next != NULL) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
flag = 1;
index1 = head;
index2 = slow;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
}
if (flag == 1) return index1;
}
return NULL;
}
};