From 9e7e5665d52ae3c388929957af1e8bd5ff9ad5bc Mon Sep 17 00:00:00 2001 From: Manmita Das <34617961+manmita@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:25:37 +0530 Subject: [PATCH] Update divide-and-conquer-algorithm.md --- .../divide-and-conquer-algorithm.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/contrib/ds-algorithms/divide-and-conquer-algorithm.md b/contrib/ds-algorithms/divide-and-conquer-algorithm.md index b5a356ea..1aa5274a 100644 --- a/contrib/ds-algorithms/divide-and-conquer-algorithm.md +++ b/contrib/ds-algorithms/divide-and-conquer-algorithm.md @@ -50,5 +50,180 @@ print("Sorted array:", arr) ## Complexity Analysis - **Time Complexity:** O(n log n) in all cases - **Space Complexity:** O(n) additional space for the merge operation + +## Examples +### 1. Count inversions in an array +An inversion in an array is a situation where two elements a[i]a[i] and a[j]a[j] form an inversion if a[i] > a[j] and i < j.Counting the number of inversions in an array can be efficiently done using a modified merge sort algorithm. + +**Algorithm:** +- **Initialization:** We start by initializing a temporary array temp_arr of the same size as the input array arr. This temporary array is used during the merge process. +- **Recursive Division (Merge Sort):** The main function count_inversions calls merge_sort, which recursively splits the array into two halves until each subarray contains a single element. +- **Merge and Count:** Once the subarrays are reduced to single elements, the merge function merges the subarrays back together while counting inversions. + +```python +def merge(arr, temp_arr, left, mid, right): + i = left # Starting index for left subarray + j = mid + 1 # Starting index for right subarray + k = left # Starting index to be sorted + inv_count = 0 + + # Conditions to ensure that i doesn't exceed mid and j doesn't exceed right + while i <= mid and j <= right: + if arr[i] <= arr[j]: + temp_arr[k] = arr[i] + i += 1 + else: + # There are mid - i inversions, because all the remaining elements in the left subarray (arr[i], arr[i+1], ..., arr[mid]) are greater than arr[j] + temp_arr[k] = arr[j] + inv_count += (mid-i + 1) + j += 1 + k += 1 + + # Copy the remaining elements of left subarray, if any + while i <= mid: + temp_arr[k] = arr[i] + i += 1 + k += 1 + + # Copy the remaining elements of right subarray, if any + while j <= right: + temp_arr[k] = arr[j] + j += 1 + k += 1 + + # Copy the sorted subarray into original array + for i in range(left, right + 1): + arr[i] = temp_arr[i] + + return inv_count + +def merge_sort(arr, temp_arr, left, right): + inv_count = 0 + if left < right: + mid = (left + right)//2 + + inv_count += merge_sort(arr, temp_arr, left, mid) + inv_count += merge_sort(arr, temp_arr, mid + 1, right) + + inv_count += merge(arr, temp_arr, left, mid, right) + + return inv_count + +def count_inversions(arr): + temp_arr = [0]*len(arr) + return merge_sort(arr, temp_arr, 0, len(arr) - 1) + +# Test case +arr = [1, 20, 6, 4, 5] +result = count_inversions(arr) +print("Number of inversions are:", result) #output- Number of inversions are: 5 +``` +### 2. Count Reverse Pairs + +Given an array of numbers, return the count of reverse pairs. Reverse Pairs are those pairs where i2*arr[j]. + +**Algorithm:** +- **Divide the Array:** Recursively divide the array into two halves until each subarray contains a single element. +- **Count Reverse Pairs:** For each split, count the reverse pairs where arr[i]>2*arr[j] and i 2 * arr[j]: + j += 1 + inv_count += (j - (mid + 1)) + + # Merge step + i = left # Starting index for left subarray + j = mid + 1 # Starting index for right subarray + k = left # Starting index to be sorted + + while i <= mid and j <= right: + if arr[i] <= arr[j]: + temp_arr[k] = arr[i] + i += 1 + else: + temp_arr[k] = arr[j] + j += 1 + k += 1 + + while i <= mid: + temp_arr[k] = arr[i] + i += 1 + k += 1 + + while j <= right: + temp_arr[k] = arr[j] + j += 1 + k += 1 + + # Copy the sorted subarray into Original array + for i in range(left, right + 1): + arr[i] = temp_arr[i] + + return inv_count + +def merge_sort(arr, temp_arr, left, right): + inv_count = 0 + if left < right: + mid = (left + right) // 2 + + inv_count += merge_sort(arr, temp_arr, left, mid) + inv_count += merge_sort(arr, temp_arr, mid + 1, right) + + inv_count += merge(arr, temp_arr, left, mid, right) + + return inv_count + +def count_reverse_pairs(arr): + temp_arr = [0] * len(arr) + return merge_sort(arr, temp_arr, 0, len(arr) - 1) + +#Test case +arr = [3, 2, 1, 4] +count = count_reverse_pairs(arr) +print("The number of reverse pair:", count) #output- Number of reverse pair: 1 +``` + +### 3. Merge Overlapping Sub-intervals + +Given an array of intervals, merge all the overlapping intervals and return an array of non-overlapping intervals. + +**Algorithm:** +- **Sort the Intervals:** Sort the intervals based on the starting point. If two intervals have the same starting point, sort them by the ending point. +- **Initialize the Merged Intervals List:** Start with the first interval and add it to the merged intervals list. +- **Iterate and Merge:** Iterate through each interval and compare it with the last interval in the merged list.If the current interval overlaps with the last merged interval, merge them by updating the end of the last merged interval.If the current interval does not overlap, add it to the merged list as a new interval. + +```python +def merge_intervals(intervals): + if not intervals: + return [] + + # Sort intervals based on the starting point + intervals.sort(key=lambda x: x[0]) + + merged = [] + for interval in intervals: + # If merged list is empty or current interval does not overlap with the last merged interval + if not merged or merged[-1][1] < interval[0]: + merged.append(interval) + else: + # There is an overlap, so merge the current interval with the last interval in merged list + merged[-1][1] = max(merged[-1][1], interval[1]) + + return merged + +# Test case: +intervals = [[1, 3], [2, 6], [8, 10], [15, 18]] +result = merge_intervals(intervals) +print(f"Merged intervals: {result}") # output- [[1, 6], [8, 10], [15, 18]] +``` --- + +