Skip to content

Commit ae92331

Browse files
authored
Merge pull request ByteByteGoHq#10 from ongshunping/cpp-solutions-linked-lists
Add C++ solutions for Chapter 3 (Linked Lists)
2 parents 209c751 + c3cd945 commit ae92331

7 files changed

+298
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Definition of MultiLevelListNode:
3+
* class MultiLevelListNode {
4+
* public:
5+
* int val;
6+
* MultiLevelListNode* next;
7+
* MultiLevelListNode* child;
8+
* MultiLevelListNode(int val = 0, MultiLevelListNode* next = nullptr, MultiLevelListNode* child = nullptr)
9+
* : val(val), next(next), child(child) {}
10+
* };
11+
*/
12+
13+
MultiLevelListNode* flattenMultiLevelList(MultiLevelListNode* head) {
14+
if (!head) {
15+
return nullptr;
16+
}
17+
MultiLevelListNode* tail = head;
18+
// Find the tail of the linked list at the first level.
19+
while (tail->next) {
20+
tail = tail->next;
21+
}
22+
MultiLevelListNode* curr = head;
23+
// Process each node at the current level. If a node has a child linked list,
24+
// append it to the tail and then update the tail to the end of the extended
25+
// linked list. Continue until all nodes at the current level are processed.
26+
while (curr) {
27+
if (curr->child) {
28+
tail->next = curr->child;
29+
// Disconnect the child linked list from the current node.
30+
curr->child = nullptr;
31+
while (tail->next) {
32+
tail = tail->next;
33+
}
34+
}
35+
curr = curr->next;
36+
}
37+
return head;
38+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Definition of ListNode:
3+
* struct ListNode {
4+
* int val;
5+
* ListNode* next;
6+
* ListNode(int val = 0, ListNode* next = nullptr) : val(val), next(next) {}
7+
* };
8+
*/
9+
10+
ListNode* linkedListIntersection(ListNode* head_A, ListNode* head_B) {
11+
ListNode* ptr_A = head_A;
12+
ListNode* ptr_B = head_B;
13+
// Traverse through list A with 'ptr_A' and list B with 'ptr_B'
14+
// until they meet.
15+
while (ptr_A != ptr_B) {
16+
// Traverse list A -> list B by first traversing 'ptr_A' and
17+
// then, upon reaching the end of list A, continue the
18+
// traversal from the head of list B.
19+
if (ptr_A != nullptr) {
20+
ptr_A = ptr_A->next;
21+
} else {
22+
ptr_A = head_B;
23+
}
24+
// Simultaneously, traverse list B -> list A.
25+
if (ptr_B != nullptr) {
26+
ptr_B = ptr_B->next;
27+
} else {
28+
ptr_B = head_A;
29+
}
30+
}
31+
// At this point, 'ptr_A' and 'ptr_B' either point to the
32+
// intersection node or both are null if the lists do not
33+
// intersect. Return either pointer.
34+
return ptr_A;
35+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Definition of ListNode:
3+
* struct ListNode {
4+
* int val;
5+
* ListNode* next;
6+
* ListNode(int val = 0, ListNode* next = nullptr) : val(val), next(next) {}
7+
* };
8+
*/
9+
10+
ListNode* linkedListReversal(ListNode* head) {
11+
ListNode* currNode = head;
12+
ListNode* prevNode = nullptr;
13+
// Reverse the direction of each node's pointer until 'currNode'
14+
// is null.
15+
while (currNode != nullptr) {
16+
ListNode* nextNode = currNode->next;
17+
currNode->next = prevNode;
18+
prevNode = currNode;
19+
currNode = nextNode;
20+
}
21+
// 'prevNode' will be pointing at the head of the reversed linked
22+
// list.
23+
return prevNode;
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Definition of ListNode:
3+
* struct ListNode {
4+
* int val;
5+
* ListNode* next;
6+
* ListNode(int val = 0, ListNode* next = nullptr) : val(val), next(next) {}
7+
* };
8+
*/
9+
10+
ListNode* linkedListReversalRecursive(ListNode* head) {
11+
// Base cases.
12+
if (head == nullptr || head->next == nullptr) {
13+
return head;
14+
}
15+
// Recursively reverse the sublist starting from the next node.
16+
ListNode* newHead = linkedListReversalRecursive(head->next);
17+
// Connect the reversed linked list to the head node to fully
18+
// reverse the entire linked list.
19+
head->next->next = head;
20+
head->next = nullptr;
21+
return newHead;
22+
}

cpp/Linked Lists/lru_cache.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <unordered_map>
2+
3+
class DoublyLinkedListNode {
4+
public:
5+
int key;
6+
int val;
7+
DoublyLinkedListNode* prev;
8+
DoublyLinkedListNode* next;
9+
DoublyLinkedListNode(int key, int val)
10+
: key(key), val(val), prev(nullptr), next(nullptr) {}
11+
};
12+
13+
class LRUCache {
14+
public:
15+
int capacity;
16+
// A hash map that maps keys to nodes.
17+
std::unordered_map<int, DoublyLinkedListNode*> hashmap;
18+
// Initialize the head and tail dummy nodes and connect them to
19+
// each other to establish a basic two-node doubly linked list.
20+
DoublyLinkedListNode* head;
21+
DoublyLinkedListNode* tail;
22+
LRUCache(int capacity) : capacity(capacity) {
23+
head = new DoublyLinkedListNode(-1, -1);
24+
tail = new DoublyLinkedListNode(-1, -1);
25+
head->next = tail;
26+
tail->prev = head;
27+
}
28+
// Destructor: Cleans up dynamically allocated resources
29+
// to prevent memory leaks. Implemented if time permits
30+
// during an interview.
31+
~LRUCache() {
32+
// Delete all nodes in the linked list.
33+
DoublyLinkedListNode* current = head;
34+
while (current != nullptr) {
35+
DoublyLinkedListNode* nextNode = current->next;
36+
delete current;
37+
current = nextNode;
38+
}
39+
// Clear the hashmap.
40+
hashmap.clear();
41+
}
42+
43+
int get(int key) {
44+
if (hashmap.find(key) == hashmap.end()) {
45+
return -1;
46+
}
47+
// To make this key the most recently used, remove its node and
48+
// re-add it to the tail of the linked list.
49+
removeNode(hashmap[key]);
50+
addToTail(hashmap[key]);
51+
return hashmap[key]->val;
52+
}
53+
54+
void put(int key, int val) {
55+
// If a node with this key already exists, remove it from the
56+
// linked list.
57+
if (hashmap.find(key) != hashmap.end()) {
58+
DoublyLinkedListNode* existingNode = hashmap[key];
59+
removeNode(existingNode);
60+
delete existingNode;
61+
hashmap.erase(key);
62+
}
63+
DoublyLinkedListNode* node = new DoublyLinkedListNode(key, val);
64+
hashmap[key] = node;
65+
// Remove the least recently used node from the cache if adding
66+
// this new node will result in an overflow.
67+
if (hashmap.size() > capacity) {
68+
DoublyLinkedListNode* lruNode = head->next;
69+
hashmap.erase(lruNode->key);
70+
removeNode(lruNode);
71+
delete lruNode;
72+
}
73+
addToTail(node);
74+
}
75+
76+
void addToTail(DoublyLinkedListNode* node) {
77+
DoublyLinkedListNode* prevNode = tail->prev;
78+
node->prev = prevNode;
79+
node->next = tail;
80+
prevNode->next = node;
81+
tail->prev = node;
82+
}
83+
84+
void removeNode(DoublyLinkedListNode* node) {
85+
node->prev->next = node->next;
86+
node->next->prev = node->prev;
87+
}
88+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Definition of ListNode:
3+
* struct ListNode {
4+
* int val;
5+
* ListNode* next;
6+
* ListNode(int val = 0, ListNode* next = nullptr) : val(val), next(next) {}
7+
* };
8+
*/
9+
10+
// Function prototypes
11+
ListNode* findMiddle(ListNode* head);
12+
ListNode* reverseList(ListNode* head);
13+
bool palindromicLinkedList(ListNode* head);
14+
15+
bool palindromicLinkedList(ListNode* head) {
16+
// Find the middle of the linked list and then reverse the second half of the
17+
// linked list starting at this midpoint.
18+
ListNode* mid = findMiddle(head);
19+
ListNode* secondHead = reverseList(mid);
20+
// Compare the first half and the reversed second half of the list
21+
ListNode* ptr1 = head;
22+
ListNode* ptr2 = secondHead;
23+
bool res = true;
24+
while (ptr2) {
25+
if (ptr1->val != ptr2->val) {
26+
res = false;
27+
}
28+
ptr1 = ptr1->next;
29+
ptr2 = ptr2->next;
30+
}
31+
return res;
32+
}
33+
34+
// From the 'Reverse Linked List' problem.
35+
ListNode* reverseList(ListNode* head) {
36+
ListNode* prevNode = nullptr;
37+
ListNode* currNode = head;
38+
while (currNode) {
39+
ListNode* nextNode = currNode->next;
40+
currNode->next = prevNode;
41+
prevNode = currNode;
42+
currNode = nextNode;
43+
}
44+
return prevNode;
45+
}
46+
47+
// From the 'Linked List Midpoint' problem.
48+
ListNode* findMiddle(ListNode* head) {
49+
ListNode* slow = head;
50+
ListNode* fast = head;
51+
while (fast != nullptr && fast->next != nullptr) {
52+
slow = slow->next;
53+
fast = fast->next->next;
54+
}
55+
return slow;
56+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Definition of ListNode:
3+
* struct ListNode {
4+
* int val;
5+
* ListNode* next;
6+
* ListNode(int val = 0, ListNode* next = nullptr) : val(val), next(next) {}
7+
* };
8+
*/
9+
10+
ListNode* removeKthLastNode(ListNode* head, int k) {
11+
// A dummy node to ensure there's a node before 'head' in case we
12+
// need to remove the head node.
13+
ListNode dummy(-1);
14+
dummy.next = head;
15+
ListNode* trailer = &dummy;
16+
ListNode* leader = &dummy;
17+
// Advance 'leader' k steps ahead.
18+
for (int i = 0; i < k; i++) {
19+
leader = leader->next;
20+
// If k is larger than the length of the linked list, no node
21+
// needs to be removed.
22+
if (leader == nullptr) {
23+
return head;
24+
}
25+
}
26+
// Move 'leader' to the end of the linked list, keeping 'trailer'
27+
// k nodes behind.
28+
while (leader->next != nullptr) {
29+
leader = leader->next;
30+
trailer = trailer->next;
31+
}
32+
// Remove the kth node from the end.
33+
trailer->next = trailer->next->next;
34+
return dummy.next;
35+
}

0 commit comments

Comments
 (0)