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;
}
}