# Linked List 2: Sorting and Detecting Loop
---
### Question
What is the time complexity needed to delete a node from a linked list?
**Choices**
- [ ] O(1)
- [ ] O(log(N))
- [x] O(N)
- [ ] O(N^2)
#### Explanation
To delete a node from the linked list we need to traverse till that node. In the worst case, the time-complexity would be O(N).
---
### Question
What is the time complexity needed to insert a node as the head of a linked list?
**Choices**
- [x] O(1)
- [ ] O(log(N))
- [ ] O(N)
- [ ] O(N$^2$)
**Explanation**
No traversal is needed to reach the head node. Therefore the time complexity needed is constant i.e. O(1).
---
### Question
What is the time complexity needed to delete the last node from a linked list?
**Choices**
- [ ] O(1)
- [ ] O(log(N))
- [x] O(N)
- [ ] O(N$^2$)
**Explanation:**
To delete the last node from the linked list we need to traverse till that node. In that case, the time-complexity would be O(N).
---
### Question
Can we do Binary Search in a sorted Linked List?
**Choices**
- [ ] Yes
- [x] No
**Explanation:**
Binary search relies on random access to elements, which is not possible in a linked list.
---
### Problem 1 Find the middle element.
Given a Linked List, Find the middle element.
**Examples**
Following 0 based indexing: The middle node is the node having the index (n / 2), where n is the number of nodes.
```cpp
Input: [1 -> 2 -> 3 -> 4 -> 5]
Output: [3]
Here 3 is the middle element
```
```cpp
Input: [1 -> 2 -> 3 -> 4]
Output: [2]
There are two middle elements here: 2 and 3 respectively.
```
---
:::warning
Please take some time to think about the solution approach on your own before reading further.....
:::
### Find the middle element Solution
#### Solution
* First, We will find the length of the linked-list.
* Now we will traverse half the length to find the middle node
#### Pseudocode
```cpp
function findMiddle(head)
if head is null
return null
count = 0
current = head
while current is not null
count = count + 1
current = current.next
middleIndex = count / 2
current = head
for i = 0 to middleIndex - 1
current = current.next
return current
}
```
#### Complexity
**Time Complexity:** O(n * 2) = O(n)
**Space Complexity:** O(1)
#### Optimized Solution
We can optimize the solution using the **Two Pointers** technique.
* Take two pointers initially pointing at the head of the Linked List and name them slowPointer and fastPointer respectively.
* The fastPointer will travel two nodes at a time, whereas the slowPointer will traverse a single node at a time
* When the fastPointer reaches the end node, the slowPointer must necessarily be pointing at the middle node
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/053/464/original/upload_11f71a7c2d1ec9ad9294aa1d8cb91211.png?1697176856" width=700/>
#### Pseudocode
```java
function findMiddleTwoPointers(head)
if head is null
return null
slowPointer = head
fastPointer = head
while fastPointer is not null and fastPointer.next is not null
slowPointer = slowPointer.next
fastPointer = fastPointer.next.next
return slowPointer
```
#### Complexity
**Time Complexity:** O(n / 2) = O(n)
**Space Complexity:** O(1)
---
### Problem 2 Merge two sorted Linked Lists
Given two sorted Linked Lists, Merge them into a single sorted linked list.
**Example 1 :**
```cpp
Input: [1 -> 2 -> 8 -> 10], [3 -> 5 -> 9 -> 11]
Output: [1 -> 2 -> 3 -> 8 -> 9 -> 10 -> 11]
```
**Example 2 :**
```cpp
Input: [1 -> 7 -> 8 -> 9], [2 -> 5 -> 10 -> 11]
Output: [1 -> 2 -> 5 -> 7 -> 8 -> 9 -> 11]
```
---
### Question
Given two sorted Linked Lists, Merge them into a single sorted linked list.
`Input: [2 -> 10 -> 11] [1 -> 5 -> 12 -> 15]`
**Choices**
- [x] [1 -> 2 -> 5 -> 10 -> 11 -> 12 -> 15]
- [ ] [2 -> 10 -> 11 -> 1 -> 5 -> 12 -> 15]
- [ ] [1 -> 5 -> 12 -> 15 -> 2 -> 10 -> 11]
- [ ] [1 -> 2 -> 10 -> 5 -> 12 -> 11 -> 15]
---
:::warning
Please take some time to think about the solution approach on your own before reading further.....
:::
### Merge two sorted Linked Lists Solution
#### Solution
* Base Cases Handling: First of all, we need to take care of the Base cases: if either list is empty,we return the other list
* Determine Merged List's Head: The algorithm compares the first nodes of the two lists. The smaller node becomes the head of the merged list.
* Merge the Remaining Nodes:Merge the remaining nodes in such a way that whichever linked lists node is the smallest, we add it to the current list
* We continue doing this till the end of one of the linked lists is reached
* Finally we attach any remaining nodes from list1 or list2
* Returning the Result: We return the linked list
#### Pseudocode
```cpp
function mergeSortedLists(list1, list2)
if list1 is null
return list2
if list2 is null
return list1
mergedList = null
if list1.data <= list2.data
mergedList = list1
list1 = list1.next
else
mergedList = list2
list2 = list2.next
current = mergedList
while list1 is not null and list2 is not null
if list1.data <= list2.data
current.next = list1
list1 = list1.next
else
current.next = list2
list2 = list2.next
current = current.next
if list1 is not null
current.next = list1
if list2 is not null
current.next = list2
return mergedList
}
```
#### Complexity
**Time Complexity:** O(n + m)
**Space Complexity:** O(1)
---
### Problem 3 Sort a Linked List
A Linked List is given, Sort the Linked list using merge sort.
**Example**
```cpp
Input: [1 -> 2 -> 5 -> 4 -> 3]
Output: [1 -> 2 -> 3 -> 4 -> 5]
```
```cpp
Input: [1 -> 4 -> 3 -> 2]
Output: [1 -> 2 -> 3 -> 4]
```
#### Solution
**Base Case:**<br> The function starts by checking if the head of the linked list is null or if it has only one element (i.e., head.next is null). These are the base cases for the recursion. If either of these conditions is met, it means that the list is already sorted (either empty or has only one element), so the function simply returns the head itself.
**Find the Middle Node:**<br> If the base case is not met, the function proceeds to sort the list. First, it calls the findMiddle function to find the middle node of the current list. This step is essential for dividing the list into two halves for sorting.
**Split the List:**<br> After finding the middle node (middle), the function creates a new pointer nextToMiddle to store the next node after the middle node. Then, it severs the connection between the middle node and the next node by setting middle.next to null. This effectively splits the list into two separate sublists: left, which starts from head and ends at middle, and right, which starts from nextToMiddle.
**Recursively Sort Both Halves:**<br> The function now recursively calls itself on both left and right sublists. This recursive step continues until each sublist reaches the base case (empty or one element). Each recursive call sorts its respective sublist.
**Merge the Sorted Halves:**<br> Once the recursive calls return and both left and right sublists are sorted, the function uses the mergeSortedLists function to merge these two sorted sublists into a single sorted list. This merging process combines the elements from left and right in ascending order.
**Return the Sorted List:**<br> Finally, the function returns the sortedList, which is the fully sorted linked list obtained by merging the sorted left and right sublists
#### Pseudocode
```cpp
// Function to merge two sorted linked lists
function mergeSortedLists(list1, list2)
if list1 is null
return list2
if list2 is null
return list1
mergedList = null
if list1.data <= list2.data
mergedList = list1
mergedList.next = mergeSortedLists(list1.next, list2)
else
mergedList = list2
mergedList.next = mergeSortedLists(list1, list2.next)
return mergedList
function findMiddle(head)
if head is null or head.next is null
return head
slow = head
fast = head.next
while fast is not null and fast.next is not null
slow = slow.next
fast = fast.next.next
return slow
function mergeSort(head)
if head is null or head.next is null
return head
// Find the middle node
middle = findMiddle(head)
nextToMiddle = middle.next
middle.next = null
// Recursively sort both halves
left = mergeSort(head)
right = mergeSort(nextToMiddle)
// Merge the sorted halves
sortedList = mergeSortedLists(left, right)
return sortedList
```
#### Complexity
**Time Complexity:** O(Nlog(N))
**Space Complexity:** O(log(N))
---
### Problem 4 Detect Cycle in a Linked List.
Given a Linked List, Find whether it contains a cycle.
**Example 1**
**Input:**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/053/470/original/upload_fd21b14f9b526a9dee6af96d7c9f5f3d.gif?1697177234" width=800/>
**Output:**
```plaintext
Yes
```
**Example 2**
**Input:**
Input: [1 -> 4 -> 3 -> 2 -> 11 -> 45 -> 99]
**Output:**
```plaintext
No
```
---
### Detect Cycle in a Linked List Solution
#### Solution
* **Initialization:**<br> Start with two pointers, slow and fast, both pointing to the head of the linked list.
* **Traversal:**<br> In each iteration, the slow pointer advances by one step, while the fast pointer advances by two steps. This mimics the tortoise and hare analogy. If there is a cycle, these two pointers will eventually meet at some point within the cycle.
* **Cycle Detection:**<br> While traversing, if the slow pointer becomes equal to the fast pointer, this indicates that the linked list contains a cycle. This is because the fast pointer "catches up" to the slow pointer within the cycle.
* **No Cycle Check:**<br> If the fast pointer reaches the end of the linked list and becomes null or if the fast pointer's next becomes nullp, this means there is no cycle in the linked list.
* **Cycle Detected:**<br> If the slow and fast pointers meet, it implies that the linked list contains a cycle. The function returns true.
#### Pseudo Code
```cpp
function hasCycle(head)
if head is null or head.next is null
return false // No cycle in an empty or single-node list
slow = head
fast = head.next
while fast is not null and fast.next is not null
if slow is the same as fast
return true // Cycle detected
slow = slow.next
fast = fast.next.next
return false // No cycle detected
```
#### Complexity
**Time Complexity:** O(N)
**Space Complexity:** O(1)
---
### Problem 5 Find the starting point
Given a Linked List which contains a cycle , Find the start point of the cycle.
**Example**
**Input:**
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/053/471/original/upload_627b814b08d3cc13417de9d895cf1446.gif?1697177500" width=500/>
**Output:**
```plaintext
5
```
---
### Find the starting point Solution
:::warning
Please take some time to think about the solution approach on your own before reading further.....
:::
#### Solution
* **Initialization:**<br> Similar to cycle detection, start with two pointers, slow and fast, both pointing to the head of the linked list.
* **Cycle Detection:**<br> In each iteration, move the slow pointer by one step and the fast pointer by two steps. If a cycle exists, they will eventually meet within the cycle.
* **Meeting Point:**<br> If a cycle is detected (slow meets fast), set a flag hasCycle to true.
* **Start Point Identification:**<br> Reset the slow pointer to the head of the list while keeping the fast pointer at the meeting point. Advance both pointers by one step in each iteration. They will eventually meet at the start point of the cycle.
* **Returning the Result:**<br> Once the slow and fast pointers meet again, it implies that the linked list has a cycle, and the meeting point is the start of the cycle. Return this pointer.
Assume that the length from the head to the first node of cycle is x and the distance from the first node of cycle to the meeting point is y. Also the length from the meeting point to the first node is z.
Now, speed of the fast pointer is twice the slow pointer
```cpp
2(x + y) = x + y + z + y
x = z
```
<img src="https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/053/481/original/upload_53a9113ef4baf57965effd9d80628c34.png?1697178095" width=700/>
* **No Cycle Check:** If the fast pointer reaches the end of the linked list (i.e., becomes nullptr) or if the fast pointer's next becomes nullptr, there is no cycle. In such cases, return nullptr.
This approach ensures that you can find the start point of the cycle using the Floyd's Tortoise and Hare algorithm with a slightly modified process.
#### Pseudo Code
```cpp
function detectCycleStart(head)
if head is null or head.next is null
return null // No cycle in an empty or single-node list
slow = head
fast = head
hasCycle = false
while fast is not null and fast.next is not null
slow = slow.next
fast = fast.next.next
if slow is the same as fast
hasCycle = true
break
if not hasCycle
return null // No cycle detected
slow = head
while slow is not the same as fast
slow = slow.next
fast = fast.next
return slow // Return the start point of the cycle
```
#### Complexity
**Time Complexity:** O(N)
**Space Complexity:** O(1)