用快慢指针找到链表的中点
“定制”三种不同的情况
1.元素个数为偶数时,慢指针指向中间偏左的元素
2.元素个数为偶数时,慢指针指向中间偏右的元素
3.慢指针指向中间的前一个元素
代码:
//1.元素个数为偶数时,慢指针指向中间偏左的元素
ListNode* EndOfFirstHalf1(ListNode* head)
{
ListNode* fast = head;
ListNode* slow = head;
while(fast->next!=nullptr)
{
fast = fast->next;
if (fast->next != nullptr)
{
slow = slow->next;
fast = fast->next;
}
else
break;
}
return slow;
}
第一种情况,只有在快指针顺利移动两次时,慢指针才移动一次
ListNode* EndOfFirstHalf2(ListNode* head)
{
ListNode* fast = head;
ListNode* slow = head;
while (fast->next != nullptr)
{
fast = fast->next;
slow = slow->next;
//先移动慢指针,再进行快指针的第二次移动
if (fast->next != nullptr)
{
fast = fast->next;
}
else
break;
}
return slow;
}
第二种情况,即使快指针只能移动一次,慢指针也移动
//3.慢指针指向中间的前一个元素
//这种情况也就是在第一种情况的基础上,慢指针在开始时就少移动一次
ListNode* EndOfFirstHalf3(ListNode* head)
{
ListNode* fast = head->next->next;
ListNode* slow = head;
while (fast->next != nullptr)
{
fast = fast->next;
if (fast->next != nullptr)
{
slow = slow->next;
fast = fast->next;
}
else
break;
}
return slow;
}
第三种情况,即在第一种情况的基础上,慢指针在开始时就少移动一次
回文链表
笔试写法:双链表+栈
例题:复制含有随即指针结点的链表(力扣138题)
使用额外空间
哈希表
key(ListNode) | value (ListNode) |
---|---|
老结点 | 对应的克隆出的新节点 |
首先不用管结点间的关系,直接复制结点,再遍历
class Solution {
public:
Node* copyRandomList(Node* head) {
unordered_map<Node*,Node*> m;
Node *p=head;
//首先复制结点
while(p!=nullptr)
{
Node* pnew=new Node(p->val);
m.insert(make_pair(p,pnew));
p=p->next;
}
//构造结点间的关系
p=head;
while(p!=nullptr)
{
Node* pnew=m[p];
pnew->next=m[p->next];
pnew->random=m[p->random];
p=p->next;
}
return m[head];
}
};
不使用额外空间
直接复制,将复制后的结点放在原结点的后面
//不使用额外空间
class Solution {
public:
Node* copyRandomList(Node* head) {
if (!head) return nullptr;
Node* cur = head;
//首先复制结点,并将新结点置于旧结点之后
while (cur != nullptr)
{
Node* next = cur->next;
cur->next = new Node(cur->val);
cur->next->next = next;
cur = next;
}
//构建random关系
cur = head;
Node* ans = head->next;
while (cur != nullptr)
{
Node* newp = cur->next;
Node* next = newp->next;
if (cur->random) newp->random = cur->random->next;
cur = next;
}
//分离
cur = head;
while (cur != nullptr)
{
Node* newp = cur->next;
Node* next = newp->next;
cur->next = next;
if (next) newp->next = next->next;
cur = next;
}
return ans;
}
};
例题:链表中环的入口节点
快慢指针
快指针走两步,慢指针走一步;当相遇时,快指针返回头结点,两个结点都每次走一步,再次相遇的位置即入口节点
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* LF=head;
ListNode* LS=head;
while(LF!=nullptr)
{
LF=LF->next;
LS=LS->next;
if(LF)
{
LF=LF->next;
if(LF==LS)//相遇
{
LF=head;
while(LF!=LS)
{
LF=LF->next;
LS=LS->next;
}
return LF;
}
}
else return nullptr;
}
return nullptr;
}
};
例题:链表相交
1.都无环:
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
ListNode* pA = headA, * pB = headB;
while (pA != nullptr || pB != nullptr)
{
if (pA == pB) return pA;
if (pA == nullptr) pA = headB;
else if (pB == nullptr) pB = headA;
else
{
pA = pA->next;
pB = pB->next;
}
}
return nullptr;
}
};