链表详解
题目链接:24. 两两交换链表中的节点
c++代码(快慢指针)
/**
* 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) {
ListNode* freshhead = new ListNode(0);
freshhead->next = head;
ListNode* cnt = freshhead;//要改变链表中的东西一般使用虚拟头结点
while (cnt->next != NULL && cnt->next->next != NULL) {//覆盖链表
ListNode* a = cnt->next;
ListNode* b = cnt->next->next;//往后推
cnt->next = b;
a->next = b->next;
b->next = a;
cnt = cnt->next->next;
}
head = freshhead->next;
delete freshhead;
return head;
}
};
思路:
三个步骤
- 步骤一:头指针(虚拟头结点)先要指向2,不然后面找不到头结点了
- 步骤二:2结点指向1结点
- 步骤三:1结点指向3结点
顺序不能变,因为第二步可能会用到第三步的东西
代码解释:
1. cnt->next = b;
2. a->next = b->next;
3. b->next = a;
4. cnt = cnt->next->next;
- 第一个结点(一开始为虚拟头结点)的下一个变成了b
- a的下一个变成了b的下一个
- b的下一个变成了a
- 往后走两个,别名变化(但空间与下面指向相同)
题目链接:19. 删除链表的倒数第 N 个结点
c++暴力解法(双指针二刷再看)
/**
* 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* freshhead = new ListNode(0);
freshhead->next = head;
ListNode* cur = freshhead;
int len = 0;
while (cur->next != NULL) {
len++;
cur = cur->next;
}
int gap = len -n;
cur = freshhead;
while (gap--) {
cur = cur->next;
}
ListNode* snode = cur->next;
cur->next = cur->next->next;
delete snode;
head = freshhead->next;
delete freshhead;
return head;
}
};
思路:
- 先算出整个链表的长度
- 与n相减得到正序删除的index
- 然后就可以用前面学的删除结点了(虚拟头结点)
代码:
cur取别名储存当前位置,防止找不到头,更方便,与下面的那块空间一样
题目链接:面试题 02.07. 链表相交
c++代码
/**
* 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) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
while (curA != NULL) {
lenA++;
curA = curA->next;
}//A长度
while (curB != NULL) {
lenB++;
curB = curB->next;
}//B长度
curA = headA;
curB = headB;
if (lenA < lenB) {
swap(lenA, lenB);
swap(curA, curB);//更换两个指向(别名交换)
}
int gap = lenA - lenB;//长度差
while (gap--) {
curA = curA->next;
}//让两指针都从相同末尾长度遍历
while (lenB--) {
if(curA == curB) {//如果空间相等的话,后面的连接也相等因为链表他们只能包含一个地址,指向一块空间
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
思路:
- 题目含义:找到后面长度,值相等的一节的第一个指针,所以必须在末尾长度相同的地方开始找.如下curA和curB
步骤
- 算出两个链表的长度
- 算出长度差,如果curA长度更长就交换两个链表(为后续操作提供便捷)
- 让curA往后移到后curB相对的位置遍历(后面都是两个长度),找到指向同个空间的地址(如上述2)
- 返回这个地址
代码:
1.curA = headA;
curB = headB;
if (lenA < lenB) {
swap(lenA, lenB);
2.swap(curA, curB);//更换两个指向(别名交换)
}
- 这段代码开始又为headA,headB取了别名,重置了
- 交换别名,指向换了
while (gap--) {
curA = curA->next;
}//让两指针都从相同末尾长度遍历
- 指向(位置)不断后推,直到后面长度为curB时开始比较
为什么curA==curB就行了
因为不存在环,所以当找到一块相同的空间,地址相同,下一块地址也会相同,因为只会指向一个地址
题目链接:142. 环形链表 II
c++代码(双指针)
/**
* 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* slow = head;
ListNode* fast = head;
while (fast != NULL && fast->next != NULL) {//判断有没有环,只要每个结点都判断就对了
fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
ListNode* index1 = slow;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2;
}
}
return NULL;
}
};
流动图:
思路:-------------------》具体解析链接,下面是精华
- 判断链表是否有环
定义两个指针slow和fast,都从头指针开始遍历,如果相遇就一定有环,因为fast进入环中就出不去了,一直转圈。
while (fast != NULL && fast->next != NULL) {//判断有没有环,出去了就没环
- 如果有环,如何找到这个环的入口
只要求出一个快指针在相遇点,慢指针在起点他们相遇(一定在入口相遇)走的长度就是要求的x了
步骤
- 两个指针都从起点开始,找到相遇点位置
- 快指针在相遇点出发,慢指针在起点出发,求出慢指针走的路
代码
while (fast != NULL && fast->next != NULL)
- 看有没有环