From 14a3a3c7906184649683826bc893aecc6d8c2002 Mon Sep 17 00:00:00 2001 From: kashvi7440 Date: Sun, 14 Jul 2024 14:10:59 +0530 Subject: [PATCH 1/4] added solution for leetcode problem number 138 --- .../138-copy-list-with-random-pointer.md | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md diff --git a/dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md b/dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md new file mode 100644 index 000000000..2b355a6ff --- /dev/null +++ b/dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md @@ -0,0 +1,227 @@ +--- + +id: copy-list-with-random-pointer +title: Copy List With Random Pointer +level: medium +sidebar_label: Copy List With Random Pointer +tags: + - Hash Table + - Linked List + - Java + - Python + - C++ +description: "This document provides solutions for the Copy List With Random Pointer problem on LeetCode." + +--- + +## Problem Description + +A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. + +Construct a deep copy of the list. + +### Examples + +**Example 1:** +``` +Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]] +Output: [[7,null],[13,0],[11,4],[10,2],[1,0]] +``` + +**Example 2:** +``` +Input: head = [[1,1],[2,1]] +Output: [[1,1],[2,1]] +``` + +**Example 3:** +``` +Input: head = [[3,null],[3,0],[3,null]] +Output: [[3,null],[3,0],[3,null]] +``` + +### Constraints: + +- The number of nodes in the list is in the range [0, 1000]. +- -10000 <= Node.val <= 10000 +- Node.random is null or is pointing to a node in the linked list. + +--- + +## Approach to Solve the Copy List with Random Pointer Problem + +To create a deep copy of a linked list with an additional random pointer, follow these steps: + +### Approach + +1. **Create Clones Adjacent to Original Nodes:** + - Iterate through the original list and create a new node for each original node. Insert this new node right next to the original node. This way, each original node will have its clone right next to it. + +2. **Assign Random Pointers to Cloned Nodes:** + - Iterate through the list again. For each original node, if it has a random pointer, set the random pointer of the clone node to point to the clone of the node that the original node’s random pointer is pointing to. This can be achieved because the clone of any node `A` is next to `A`. + +3. **Restore the Original List and Extract the Cloned List:** + - Iterate through the list once more to restore the original list by separating the original nodes from their clones. Extract the cloned list by linking the cloned nodes together. + +#### Code in Different Languages + +### C++ +```cpp +class Node { +public: + int val; + Node* next; + Node* random; + + Node(int _val) { + val = _val; + next = NULL; + random = NULL; + } +}; + +class Solution { +public: + Node* copyRandomList(Node* head) { + if (!head) return nullptr; + + // Step 1: Create a new node for each original node and insert it next to the original node. + Node* curr = head; + while (curr) { + Node* newNode = new Node(curr->val); + newNode->next = curr->next; + curr->next = newNode; + curr = newNode->next; + } + + // Step 2: Assign random pointers for the new nodes. + curr = head; + while (curr) { + if (curr->random) { + curr->next->random = curr->random->next; + } + curr = curr->next->next; + } + + // Step 3: Restore the original list and extract the copied list. + curr = head; + Node* copiedHead = head->next; + Node* copiedCurr = copiedHead; + while (curr) { + curr->next = curr->next->next; + if (copiedCurr->next) { + copiedCurr->next = copiedCurr->next->next; + } + curr = curr->next; + copiedCurr = copiedCurr->next; + } + + return copiedHead; + } +}; +``` + +### Java +```java +class Node { + int val; + Node next; + Node random; + + public Node(int val) { + this.val = val; + this.next = null; + this.random = null; + } +} + +class Solution { + public Node copyRandomList(Node head) { + if (head == null) return null; + + // Step 1: Create a new node for each original node and insert it next to the original node. + Node curr = head; + while (curr != null) { + Node newNode = new Node(curr.val); + newNode.next = curr.next; + curr.next = newNode; + curr = newNode.next; + } + + // Step 2: Assign random pointers for the new nodes. + curr = head; + while (curr != null) { + if (curr.random != null) { + curr.next.random = curr.random.next; + } + curr = curr.next.next; + } + + // Step 3: Restore the original list and extract the copied list. + curr = head; + Node copiedHead = head.next; + Node copiedCurr = copiedHead; + while (curr != null) { + curr.next = curr.next.next; + if (copiedCurr.next != null) { + copiedCurr.next = copiedCurr.next.next; + } + curr = curr.next; + copiedCurr = copiedCurr.next; + } + + return copiedHead; + } +} +``` + +### Python +```python +class Node: + def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None): + self.val = x + self.next = next + self.random = random + +class Solution: + def copyRandomList(self, head: 'Node') -> 'Node': + if not head: + return None + + # Step 1: Create a new node for each original node and insert it next to the original node. + curr = head + while curr: + newNode = Node(curr.val) + newNode.next = curr.next + curr.next = newNode + curr = newNode.next + + # Step 2: Assign random pointers for the new nodes. + curr = head + while curr: + if curr.random: + curr.next.random = curr.random.next + curr = curr.next.next + + # Step 3: Restore the original list and extract the copied list. + curr = head + copiedHead = head.next + copiedCurr = copiedHead + while curr: + curr.next = curr.next.next + if copiedCurr.next: + copiedCurr.next = copiedCurr.next.next + curr = curr.next + copiedCurr = copiedCurr.next + + return copiedHead +``` + +### Complexity + +- **Time Complexity:** $O(n)$ - Each of the three steps involves a single pass through the list. +- **Space Complexity:** $O(1)$ - The space complexity is constant as we are not using any additional data structures for storage. + +### Summary + +This approach efficiently creates a deep copy of a linked list with random pointers by leveraging the existing structure of the list and ensuring that each node and its clone are linked adjacently. \ No newline at end of file From 08db92d7cb0830eefaf6c3b126e989a08785917d Mon Sep 17 00:00:00 2001 From: kashvi7440 Date: Mon, 15 Jul 2024 16:52:26 +0530 Subject: [PATCH 2/4] Added solution to leetcode problem no 1114 --- ... => 0138-copy-list-with-random-pointer.md} | 0 .../1000-1099/1114-print-in-order.md | 172 ++++++++++++++++++ 2 files changed, 172 insertions(+) rename dsa-solutions/lc-solutions/0100-0199/{138-copy-list-with-random-pointer.md => 0138-copy-list-with-random-pointer.md} (100%) create mode 100644 dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md diff --git a/dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md b/dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md similarity index 100% rename from dsa-solutions/lc-solutions/0100-0199/138-copy-list-with-random-pointer.md rename to dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md diff --git a/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md b/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md new file mode 100644 index 000000000..989242e44 --- /dev/null +++ b/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md @@ -0,0 +1,172 @@ +--- + +id: print-in-order +title: Print in Order +level: medium +sidebar_label: Print in Order +tags: + - Concurrency + - Threads + - Java + - Python + - C++ +description: "This document provides solutions for the Print in Order problem on LeetCode." + +--- + +## Problem Description + +Suppose we have a class: + +```java +class Foo { + public void first() { print("first"); } + public void second() { print("second"); } + public void third() { print("third"); } +} +``` + +The same instance of `Foo` will be passed to three different threads. Thread A will call `first()`, thread B will call `second()`, and thread C will call `third()`. Design a mechanism and modify the program to ensure that `second()` is executed after `first()`, and `third()` is executed after `second()`. + +### Examples + +**Example 1:** +``` +Input: [1,2,3] +Output: "firstsecondthird" +``` + +**Example 2:** +``` +Input: [1,3,2] +Output: "firstsecondthird" +``` + +### Constraints: + +- The input array is a permutation of [1, 2, 3]. + +--- + +## Approach to Solve the Print in Order Problem + +To ensure that the methods are executed in the correct order, we can use synchronization mechanisms such as locks, condition variables, or semaphores. + +### Approach + +1. **Using Locks and Condition Variables:** + - Use a lock to ensure mutual exclusion. + - Use condition variables to signal when a method can proceed. + +2. **Using Semaphores:** + - Use semaphores to control the order of execution. + - Initialize semaphores in such a way that they ensure the correct sequence. + +#### Code in Different Languages + +### C++ +```cpp +#include +#include +#include +#include + +class Foo { +private: + std::mutex mtx; + std::condition_variable cv; + int step; + +public: + Foo() { + step = 1; + } + + void first(std::function printFirst) { + std::unique_lock lock(mtx); + printFirst(); + step = 2; + cv.notify_all(); + } + + void second(std::function printSecond) { + std::unique_lock lock(mtx); + cv.wait(lock, [&]() { return step == 2; }); + printSecond(); + step = 3; + cv.notify_all(); + } + + void third(std::function printThird) { + std::unique_lock lock(mtx); + cv.wait(lock, [&]() { return step == 3; }); + printThird(); + } +}; +``` + +### Java +```java +import java.util.concurrent.Semaphore; + +class Foo { + private Semaphore firstDone = new Semaphore(0); + private Semaphore secondDone = new Semaphore(0); + + public Foo() { + } + + public void first(Runnable printFirst) throws InterruptedException { + printFirst.run(); + firstDone.release(); + } + + public void second(Runnable printSecond) throws InterruptedException { + firstDone.acquire(); + printSecond.run(); + secondDone.release(); + } + + public void third(Runnable printThird) throws InterruptedException { + secondDone.acquire(); + printThird.run(); + } +} +``` + +### Python +```python +from threading import Lock + +class Foo: + def __init__(self): + self.lock1 = Lock() + self.lock2 = Lock() + self.lock1.acquire() + self.lock2.acquire() + + def first(self, printFirst: 'Callable[[], None]') -> None: + # printFirst() outputs "first". Do not change or remove this line. + printFirst() + self.lock1.release() + + def second(self, printSecond: 'Callable[[], None]') -> None: + with self.lock1: + # printSecond() outputs "second". Do not change or remove this line. + printSecond() + self.lock2.release() + + def third(self, printThird: 'Callable[[], None]') -> None: + with self.lock2: + # printThird() outputs "third". Do not change or remove this line. + printThird() +``` + +### Complexity + +- **Time Complexity:** The time complexity is dependent on the time taken by the `first()`, `second()`, and `third()` methods to print their respective strings. The synchronization mechanism adds minimal overhead. +- **Space Complexity:** $O(1)$ - We are using a constant amount of space for locks and semaphores. + +### Summary + +This approach uses synchronization primitives like locks and semaphores to ensure that the methods are executed in the specified order. The use of these primitives ensures that `second()` waits for `first()` to complete, and `third()` waits for `second()` to complete, thus maintaining the required order of execution. \ No newline at end of file From e0d2384e037fa6d341ac7b5221c31503fc6b294a Mon Sep 17 00:00:00 2001 From: kashvi7440 Date: Fri, 19 Jul 2024 19:07:15 +0530 Subject: [PATCH 3/4] Added solution for leetcode problem number 138 --- .../1000-1099/1114-print-in-order.md | 172 ------------------ 1 file changed, 172 deletions(-) delete mode 100644 dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md diff --git a/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md b/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md deleted file mode 100644 index 989242e44..000000000 --- a/dsa-solutions/lc-solutions/1000-1099/1114-print-in-order.md +++ /dev/null @@ -1,172 +0,0 @@ ---- - -id: print-in-order -title: Print in Order -level: medium -sidebar_label: Print in Order -tags: - - Concurrency - - Threads - - Java - - Python - - C++ -description: "This document provides solutions for the Print in Order problem on LeetCode." - ---- - -## Problem Description - -Suppose we have a class: - -```java -class Foo { - public void first() { print("first"); } - public void second() { print("second"); } - public void third() { print("third"); } -} -``` - -The same instance of `Foo` will be passed to three different threads. Thread A will call `first()`, thread B will call `second()`, and thread C will call `third()`. Design a mechanism and modify the program to ensure that `second()` is executed after `first()`, and `third()` is executed after `second()`. - -### Examples - -**Example 1:** -``` -Input: [1,2,3] -Output: "firstsecondthird" -``` - -**Example 2:** -``` -Input: [1,3,2] -Output: "firstsecondthird" -``` - -### Constraints: - -- The input array is a permutation of [1, 2, 3]. - ---- - -## Approach to Solve the Print in Order Problem - -To ensure that the methods are executed in the correct order, we can use synchronization mechanisms such as locks, condition variables, or semaphores. - -### Approach - -1. **Using Locks and Condition Variables:** - - Use a lock to ensure mutual exclusion. - - Use condition variables to signal when a method can proceed. - -2. **Using Semaphores:** - - Use semaphores to control the order of execution. - - Initialize semaphores in such a way that they ensure the correct sequence. - -#### Code in Different Languages - -### C++ -```cpp -#include -#include -#include -#include - -class Foo { -private: - std::mutex mtx; - std::condition_variable cv; - int step; - -public: - Foo() { - step = 1; - } - - void first(std::function printFirst) { - std::unique_lock lock(mtx); - printFirst(); - step = 2; - cv.notify_all(); - } - - void second(std::function printSecond) { - std::unique_lock lock(mtx); - cv.wait(lock, [&]() { return step == 2; }); - printSecond(); - step = 3; - cv.notify_all(); - } - - void third(std::function printThird) { - std::unique_lock lock(mtx); - cv.wait(lock, [&]() { return step == 3; }); - printThird(); - } -}; -``` - -### Java -```java -import java.util.concurrent.Semaphore; - -class Foo { - private Semaphore firstDone = new Semaphore(0); - private Semaphore secondDone = new Semaphore(0); - - public Foo() { - } - - public void first(Runnable printFirst) throws InterruptedException { - printFirst.run(); - firstDone.release(); - } - - public void second(Runnable printSecond) throws InterruptedException { - firstDone.acquire(); - printSecond.run(); - secondDone.release(); - } - - public void third(Runnable printThird) throws InterruptedException { - secondDone.acquire(); - printThird.run(); - } -} -``` - -### Python -```python -from threading import Lock - -class Foo: - def __init__(self): - self.lock1 = Lock() - self.lock2 = Lock() - self.lock1.acquire() - self.lock2.acquire() - - def first(self, printFirst: 'Callable[[], None]') -> None: - # printFirst() outputs "first". Do not change or remove this line. - printFirst() - self.lock1.release() - - def second(self, printSecond: 'Callable[[], None]') -> None: - with self.lock1: - # printSecond() outputs "second". Do not change or remove this line. - printSecond() - self.lock2.release() - - def third(self, printThird: 'Callable[[], None]') -> None: - with self.lock2: - # printThird() outputs "third". Do not change or remove this line. - printThird() -``` - -### Complexity - -- **Time Complexity:** The time complexity is dependent on the time taken by the `first()`, `second()`, and `third()` methods to print their respective strings. The synchronization mechanism adds minimal overhead. -- **Space Complexity:** $O(1)$ - We are using a constant amount of space for locks and semaphores. - -### Summary - -This approach uses synchronization primitives like locks and semaphores to ensure that the methods are executed in the specified order. The use of these primitives ensures that `second()` waits for `first()` to complete, and `third()` waits for `second()` to complete, thus maintaining the required order of execution. \ No newline at end of file From d69bd38533708a7dac4306ec80d7b90c40681faa Mon Sep 17 00:00:00 2001 From: Kashvi7440 <112798525+kashvi7440@users.noreply.github.com> Date: Mon, 22 Jul 2024 23:18:16 +0530 Subject: [PATCH 4/4] Update 0138-copy-list-with-random-pointer.md Made the necessary changes. --- .../0100-0199/0138-copy-list-with-random-pointer.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md b/dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md index 2b355a6ff..c89d28116 100644 --- a/dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md +++ b/dsa-solutions/lc-solutions/0100-0199/0138-copy-list-with-random-pointer.md @@ -43,7 +43,7 @@ Output: [[3,null],[3,0],[3,null]] ### Constraints: - The number of nodes in the list is in the range [0, 1000]. -- -10000 <= Node.val <= 10000 +- `-10000 <= Node.val <= 10000` - Node.random is null or is pointing to a node in the linked list. --- @@ -224,4 +224,4 @@ class Solution: ### Summary -This approach efficiently creates a deep copy of a linked list with random pointers by leveraging the existing structure of the list and ensuring that each node and its clone are linked adjacently. \ No newline at end of file +This approach efficiently creates a deep copy of a linked list with random pointers by leveraging the existing structure of the list and ensuring that each node and its clone are linked adjacently.