1. 复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
必须返回给定的拷贝作为对克隆列表的引用。
思路:对于一个节点,它的next指针指向链表中的下一个节点。next指针将所有节点链接起来。
- 方法1:回溯
将链表想像成一张图,遍历整个图并拷贝它。当遇到一个新的未访问过的节点,创造一个新的节点。按深度优先进行遍历。
unordered_map<Node*, Node*> mp;
Node* copyRandomList(Node* head) {
if(head == nullptr)
{
return nullptr;
}
if(mp.count(head))
{
return mp[head];
}
Node* node = new Node(head -> val, nullptr, nullptr);
mp[head] = node;
node -> next = copyRandomList(head -> next);
node -> random = copyRandomList(head -> random);
return node;
}
- 方法二:一次遍历
unordered_map<Node*, Node*> mp;
Node* getClonedNode(Node* node)
{
if(node)
{
if(mp.count(node) != 0)
{
return mp[node];
}
else
{
mp[node] = new Node(node -> val, nullptr, nullptr);
return mp[node];
}
}
return nullptr;
}
Node* copyRandomList(Node* head) {
if(head == nullptr)
{
return head;
}
Node* oldNode = head;
Node* newNode = new Node(oldNode -> val, nullptr, nullptr);
mp[oldNode] = newNode;
while(oldNode)
{
newNode -> random = getClonedNode(oldNode -> random);
newNode -> next = getClonedNode(oldNode -> next);
oldNode = oldNode -> next;
newNode = newNode -> next;
}
return mp[head];
}
- 方法三:新旧交替链表
Node* copyRandomList(Node* head) {
if(head == nullptr)
{
return nullptr;
}
Node* ptr = head;
while(ptr != nullptr)
{
Node* newNode = new Node(ptr -> val);
newNode -> next = ptr -> next;
ptr -> next = newNode;
ptr = newNode -> next;
}
ptr = head;
while(ptr)
{
ptr -> next -> random = ptr -> random;
ptr = ptr -> next -> next;
}
Node* old_list = head;
Node* new_list = head -> next;
Node* res = head -> next;
while(old_list)
{
old_list -> next = old_list -> next -> next;
new_list -> next = (new_list -> next == nullptr) ? nullptr : new_list -> next -> next;
old_list = old_list -> next;
new_list = new_list -> next;
}
return res;
}
2. 环形链表II
给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null
为了表示给定链表中的环,我们使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。如果pos是-1,则在该链表中没有环。
思路:快慢指针先判断链表是否有环
当快慢指针相遇的时候,慢指针正好走过环的一圈(可以证明)
头节点到入环点的距离正好是慢指针距离入环点的距离
ListNode *detectCycle(ListNode *head) {
if(head == nullptr || head -> next == nullptr)
{
return nullptr;
}
//判断链表中是否有环
//快指针一次走两步,慢指针一次走一步
ListNode* slow = head;
ListNode * fast = head;
bool hascycle = false;
while(fast && fast -> next)
{
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow)
{
hascycle = true;
break;
}
}
//如果链表中有环,判断入环的位置
//头节点到入环点的距离与慢指针到入环点的距离相等
if(hascycle)
{
ListNode* p = head;
while(p != slow)
{
p = p -> next;
slow = slow -> next;
}
return slow;
}
else
{
return nullptr;
}
}