---
# System prepended metadata

title: Sorting
tags: [Data Structures & Algorithms, GeeksforGeeks]

---

# Sorting

TC: nLog(n)
SC: O(1) for some runtimes O(n) for speedup

Space complexity : O(N) or O(log⁡N)
- The space complexity of the sorting algorithm depends on the implementation of each programming language.
- For instance, the list.sort() function in Python is implemented with the Timsort algorithm whose space complexity is O(N).
- In Java, the Arrays.sort() is implemented as a variant of quicksort algorithm whose space complexity is O(logN).



```python
arr = [1, 30, 2, 4]
arr.sort() # asc , inplace
arr.sort(reverse = True)

arr.sort(key=lambda x: x[1])
arr.sort(key=lambda x: (x[0], x[1]) # sort by multiple keys 
```

## Problems
- merge two sorted arrays
    - Naive Solution: Create new array with size m + n. copy all items in to that array, sort them and print elements in that array.
![image](https://hackmd.io/_uploads/S19cnOLWC.png)
``` python
# TC: O(n + m)
# SC: O(1)
def merge(arr1, arr2):
    i = 0
    j = 0
    m = len(arr1)
    n = len(arr2)
    while i < m and j < n:
        # print(f'{i}/{m},{j}/{n}')
        if arr1[i] <= arr2[j]:
            print(arr1[i], end=' ')
            i += 1
        else:
            print(arr2[j], end=' ')
            j += 1 
    while j < n:
        print(arr2[j], end=' ')
        j += 1 
    while i < m:
        print(arr1[i], end=' ')
        i += 1     
    print()
arr1 = [5, 6, 6, 15]
arr2 = [10, 15, 20]
merge(arr1, arr2)
```
- intersection of two sorted arrays (skip repeated)
![image](https://hackmd.io/_uploads/rJW-2XD-C.png)

``` python
# TC: O(n + m)
# SC: O(1)
def intersection(arr1, arr2):
    i = 0
    j = 0
    m = len(arr1)
    n = len(arr2)
    while i < m and j < n:
        if i > 0 and arr1[i] == arr1[i - 1]:
            i += 1
            continue
        if j > 0 and arr2[j] == arr2[j - 1]:
            j += 1
            continue
        if arr1[i] == arr2[j]:
            print(arr1[i], end=' ')
            i += 1
            j += 1
        elif arr1[i] < arr2[j]:
            i += 1
        else:
            j += 1
    print()

arr1 = [3, 5, 10, 10, 10, 15, 15, 20]
arr2 = [5, 10, 10, 15, 30]
intersection(arr1, arr2)
```
- Union of two sorted arrays
![image](https://hackmd.io/_uploads/ByxDDAVv-R.png)
```python
# TC: O(n + m)
# SC: O(1)
def union(arr1, arr2):
    i = 0
    j = 0
    m = len(arr1)
    n = len(arr2)
    while i < m and j < n:
        if i > 0 and arr1[i] == arr1[i - 1]:
            i += 1
            continue
        if j > 0 and arr2[j] == arr2[j - 1]:
            j += 1
            continue
        if arr1[i] == arr2[j]:
            print(arr1[i], end=' ')
            i += 1
            j += 1
        elif arr1[i] < arr2[j]:
            print(arr1[i], end=' ')
            i += 1
        else:
            print(arr2[j], end=' ')
            j += 1
    
    while i < m:
        if i > 0 and arr1[i] == arr1[i - 1]:
            i += 1
            continue
        print(arr1[i], end=' ')
        i += 1
    while j < n:
        if j > 0 and arr2[j] == arr2[j - 1]:
            j += 1
            continue
        print(arr2[j], end=' ')
        j += 1
    print()

arr1 = [3, 5, 10, 10, 10, 15, 15, 20]
arr2 = [5, 10, 10, 15, 30]
union(arr1, arr2) # 3 5 10 15 20 30 
```
- Kth Smallest element 
![image](https://hackmd.io/_uploads/rk4URQw-C.png)
```python
# TC: O(nlogn)
# SC: O(1)
def kth(arr, k):
    arr.sort()
    return arr[k - 1]
```
- Minimum difference in an array 
![image](https://hackmd.io/_uploads/By2JkNvZA.png)
```python
# TC: O(nlogn)
# SC: O(1)
import math 

def min_diff(arr):
    arr.sort()
    result = math.inf
    i = 1
    while i < len(arr):
        diff = arr[i] - arr[i-1]
        result = min(result, diff)
        i += 1
    return result
```
- Chocolate distribution problem 
![image](https://hackmd.io/_uploads/H16_z4w-R.png)
``` python
# TC: O(nlogn)
# SC: O(1)
import math 

def min_k_diff(arr, k):
    arr.sort()
    result = math.inf
    i = 0
    while i + k - 1 < len(arr):
        diff = arr[i + k - 1] - arr[i]
        result = min(result, diff)
        i += 1
    return result


print(min_k_diff([7, 3, 2, 4, 9, 12, 56], 3)) # 2
print(min_k_diff([3, 4, 1, 9, 56, 7, 9, 12], 5)) # 6
```
- Sort an array with two types of elements
![image](https://hackmd.io/_uploads/B1HG_EP-R.png)
- Sort an array with three types of elements
- Merge overlapping intervals
![image](https://hackmd.io/_uploads/HJE5xmobA.png)
```python
# TC: O(n log n)
# SC: O(n)

def merge_interval(arr):
    def merge_item(item1, item2):
        x1, y1 = item1
        x2, y2 = item2
        if y1 < x2:
            return [item1, item2]
        return [(min(x1, x2), max(y1, y2))]

    arr.sort(key=lambda x: x[0])
    n = len(arr)
    result = []
    for x in range(0, n):
        if x == 0:
            result.append(arr[x])
            continue
        prev = result.pop()
        items = merge_item(prev, arr[x])
        for item in items:
            result.append(item)
    return result


print(merge_interval([(1, 3), (2, 4), (5, 7), (6, 8)])) 
print(merge_interval([(7, 9), (6, 10), (4, 5), (1, 3), (2, 4)]))
```
- Meeting the maximum guests
![image](https://hackmd.io/_uploads/r1CZ5Qsb0.png)
``` python
# TC: O(n log(n))
# SC: O(1)

def meeting_guest(arr, dep):
    arr.sort()
    dep.sort()
    n = len(arr)
    i = 0
    j = 0

    result = 0
    current = 0
    while i < n and j < n:
        if arr[i] < dep[j]:
            i += 1
            current += 1
        elif dep[j] < arr[i]:
            j += 1
            current -= 1
        elif dep[j] == arr[i]:
            j += 1
            current -= 1
        result = max(result, current)
    return result


print(meeting_guest([900, 940], [1000, 1030])) 
print(meeting_guest([800, 700, 600, 500], [840, 820, 830, 530]))
print(meeting_guest([900, 940, 950, 1100, 1500, 1800], [910, 1200, 1120, 1130, 1900, 2000]))
```