链表
单链表
设计单链表
注意:中间删除结点和中间插入结点都不难,但是任意插入或删除结点的时候需要考虑到头插或头删。要注意的是如果头结点改变了,那head结点就要改变,所以当插入结点或者删除结点的时候需要特别小心头结点的插入删除。
class MyLinkedList {
private:
struct ListNode
{
int val;
ListNode* next;
ListNode(int v = 0) :val(v), next(nullptr) {
}
};
int size;// 链表的长度
ListNode* head;// 头指针
public:
/** Initialize your data structure here. */
MyLinkedList() :size(0), head(nullptr) {
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int get(int index) {
if (index + 1 > size)
return -1;
ListNode* cur = head;
while (index--)
{
cur = cur->next;
}
return cur->val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void addAtHead(int val) {
addAtIndex(0, val);
}
/** Append a node of value val to the last element of the linked list. */
void addAtTail(int val) {
addAtIndex(size, val);
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void addAtIndex(int index, int val) {
ListNode* newNode = new ListNode(val);
// 头插
if (index <= 0)
{
newNode->next = head;// newNode指向head,然后newNode变成head
head = newNode;
size++;
return;
}
// 索引大于链表的长度
if (index > size)
return;
// 中间插入结点
ListNode* prev = head;
while (--index)// 找到index前一个结点
{
prev = prev->next;
}
newNode->next = prev->next;
prev->next = newNode;
size++;// 链表长度+1
}
/** Delete the index-th node in the linked list, if the index is valid. */
void deleteAtIndex(int index) {
if (index < 0 || index >= size)// 没有索引会<0或者>=size
return;
if (index == 0)// 删除头结点
{
ListNode* delNode = head;
head = head->next;
delete delNode;
}
else// 删除中间结点
{
ListNode* prev = head;
while (-- index)// 找到index前一个结点
{
prev = prev->next;
}
ListNode* delNode = prev->next;
prev->next = delNode->next;
delete delNode;
}
size --;// 链表长度-1
}
};
链表中的双指针
环形链表
(快慢指针)
注意一点,因为fast和slow指针初始化的时候都需要初始化为head,所以就可以用fast!=slow
来作为while循环的条件
class Solution {
public:
bool hasCycle(ListNode *head) {
if (head == nullptr || head->next == nullptr) return false;
ListNode* fast = head, *slow = head;
// 方法1
while (fast && fast->next)
{
fast = fast->next->next;// fast每次走两步
slow = slow->next;// 慢指针每次走一步
if (fast == slow)
return true;
}
return false;
// 方法2
// while (fast != nullptr)
// {
// fast = fast->next;
// if (fast != nullptr)
// fast = fast->next;
// slow = slow->next;
// if (fast == slow)
// return true;
// }
// return false;
}
};
环形链表Ⅱ
(快慢指针)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
// 判断是否有环
ListNode* fast = head, *slow = head;
ListNode* meetNode = nullptr;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
meetNode = fast;
break;
}
}
// 如果链表中没有环就返回nullptr
if (meetNode == nullptr)
return nullptr;
// 让head和meetNode同时走知道相遇,相遇的位置就是入环口
while (head != meetNode)
{
head = head->next;
meetNode = meetNode->next;
}
return meetNode;
}
};
相交链表
(指针交错遍历1)
因为相交点之后的结点数是相同的,但是相交点之前的结点数不同,如果让两个指针走的结点数相同的话就可以同时到达相交点。所以让curA指针走完curA链表之后再去走curB链表,让curB指针走完curB链表之后,去走curA链表,这样就可以弥补相交点之前结点数可能不同,而导致走的结点数不同。
概括:走到尽头见不到你,于是走过你来时的路,等到相遇时才发现,你也走过我来时的路
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA, *curB = headB;
while (curA != curB)
{
curA = curA->next;
curB = curB->next;
// 如果同时走到nullptr就说明链表没有相交点
if (curA == nullptr && curB == nullptr) return nullptr;
// 如果链表走完一条链表就再去走另一条链表
if (curA == nullptr) curA = headB;
if (curB == nullptr) curB = headA;
}
return curA;
}
};
(指针交错遍历2)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA, *curB = headB;
while (curA != curB)
{
curA = curA ? curA->next : headB;
curB = curB ? curB->next : headA;
}
return curA;
}
};
(链表相联找入环口)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
// 找到链表A的尾巴
ListNode* cur = headA;
while (cur->next != nullptr)
cur = cur->next;
// 将链表A连接到链表B上
cur->next = headB;
// 找入环口
ListNode* fast = headA, *slow = headA;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast)
{
ListNode* prev = headA;
while (prev != slow)
{
prev = prev->next;
slow = slow->next;
}
// 恢复链表
cur->next = nullptr;
return prev;
}
}
// 恢复链表
cur->next = nullptr;
return nullptr;
}
};
(补齐链表差数)
/**
* 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 cntA = 0, cntB = 0;
ListNode* curA = headA, *curB = headB;
// 统计链表的长度
while (curA)
{
curA = curA->next;
cntA ++;
}
while (curB)
{
curB = curB->next;
cntB ++;
}
// greater是长的链表,less是短的链表
ListNode* greater = cntA > cntB ? headA : headB;
ListNode* less = greater == headA ? headB : headA;
// 让长链表先走差数步,补齐差数
int n = abs(cntA - cntB);
for (int i = 0; i < n; i ++)
greater = greater->next;
// 长链表和短链表同时走,直到相遇
while (greater != less)
{
greater = greater->next;
less = less->next;
}
return greater;
}
};