Sort
Sort
- Time Complexity
- Space Complexity
- Stable, unstable
https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/
Quick Sort
private static void quickSort(int[] arr, int left, int right) {
if (left + 10 <= right) {
int pivot = medianOfThree(arr, left, right);
int low = left, high = right - 1;
while (true) {
while (arr[++low] < pivot);
while (arr[--high] > pivot);
if (low < high) swap(arr, low, high);
else break;
}
swap(arr, low, right - 1);
quickSort(arr, left, low - 1);
quickSort(arr, low + 1, right);
} else {
insertionSort(arr, left, right);
}
}
public static void quicksort(int[] arr) {
quickSort(arr, 0, arr.length - 1);
}
Quick Sort
def quick_sort(arr, left, right):
if left + 10 <= right:
pivot = median_of_three(arr, left, right)
low = left
high = right - 1
while True:
while arr[low] < pivot:
low += 1
while arr[high] > pivot:
high -= 1
if low < high:
arr[low], arr[high] = arr[high], arr[low]
else:
break
arr[low], arr[right - 1] = arr[right - 1], arr[low]
quick_sort(arr, left, low - 1)
quick_sort(arr, low + 1, right)
else:
insertion_sort(arr, left, right)
def quicksort(arr):
quick_sort(arr, 0, len(arr) - 1)
Merge Sort
void mSort(ElementType[] A, ElementType[] tmpA, int L, int rightEnd) {
// Core recursive sorting function
int center;
if (L < rightEnd) {
center = (L + rightEnd) / 2;
mSort(A, tmpA, L, center); // Recursively sort the left half
mSort(A, tmpA, center + 1, rightEnd); // Recursively sort the right half
merge(A, tmpA, L, center + 1, rightEnd); // Merge the two sorted halves
}
}
void merge(ElementType[] A, ElementType[] tmpA, int L, int R, int rightEnd) {
int leftEnd = R - 1; // Left subarray end index
int tmp = L; // Position for the sorted sequence in tmpA
int numElements = rightEnd - L + 1;
// Merge the two subarrays
while (L <= leftEnd && R <= rightEnd) {
if (A[L].compareTo(A[R]) <= 0) {
tmpA[tmp++] = A[L++]; // Copy the left element to tmpA
} else {
tmpA[tmp++] = A[R++]; // Copy the right element to tmpA
}
}
// Copy remaining elements from the left subarray, if any
while (L <= leftEnd) {
tmpA[tmp++] = A[L++];
}
// Copy remaining elements from the right subarray, if any
while (R <= rightEnd) {
tmpA[tmp++] = A[R++];
}
// Copy the sorted elements back to the original array A
for (int i = 0; i < numElements; i++, rightEnd--) {
A[rightEnd] = tmpA[rightEnd]; // Copy sorted tmpA back to A
}
}
Merge Sort
def merge_sort(A):
tmpA = [None] * len(A)
m_sort(A, tmpA, 0, len(A) - 1)
def m_sort(A, tmpA, L, rightEnd):
# Core recursive sorting function
if L < rightEnd:
center = (L + rightEnd) // 2
m_sort(A, tmpA, L, center) # Recursively sort the left half
m_sort(A, tmpA, center + 1, rightEnd) # Recursively sort the right half
merge(A, tmpA, L, center + 1, rightEnd) # Merge the two sorted halves
def merge(A, tmpA, L, R, rightEnd):
leftEnd = R - 1 # Left subarray end index
tmp = L # Position for the sorted sequence in tmpA
numElements = rightEnd - L + 1
# Merge the two subarrays
while L <= leftEnd and R <= rightEnd:
if A[L] <= A[R]:
tmpA[tmp] = A[L]
L += 1
else:
tmpA[tmp] = A[R]
R += 1
tmp += 1
# Copy remaining elements from the left subarray, if any
while L <= leftEnd:
tmpA[tmp] = A[L]
L += 1
tmp += 1
# Copy remaining elements from the right subarray, if any
while R <= rightEnd:
tmpA[tmp] = A[R]
R += 1
tmp += 1
# Copy the sorted elements back to the original array A
for i in range(numElements):
A[rightEnd] = tmpA[rightEnd]
rightEnd -= 1
Time Complexity
- O(n^2): Insertion sort, Bubble sort, Selection sort
- O(nlogn): QuickSort, MergeSort, HeapSort
- O(n): Couting Sort, Bucket Sort, Radix Sort
Time Complexity
We need to consider about the best and worst case
For example:
Best case for Bubble Sort is O(n)
Worst case for QuickSort is O(n^2)
Question: How the quicksort hit the worst case?
What if the partition is always 1:100000?
Time Complexity
The lower bound of comparison sort is O(nlogn)
Counting Sort, Bucket Sort and Radix Sort are not comparison sort.
To get O(n), you need to have some pre defined requirements for the data you want to sort.
Counting, Bucket and Radix
- These are not comparison sort
- you have some limits on the numbers you are going to sort
- Radix is just counting repeating multiple times
Space Complexity
- In-place and out-of-place
- in-place algorithm is an algorithm which transforms input using no auxiliary data structure
In-place: Bubble Sort, Insertion Sort, Selection Sort, QuickSort, HeapSort
Out-of place: Merge Sort, Counting Sort, Bucket Sort, Radix Sort
Stability
- stable sorting algorithms maintain the relative order of records with equal keys
Stable: MergeSort, Bubble Sort, Insertion Sort, Counting Sort, Bucket Sort, Radix Sort
Unstable: QuickSort, HeapSort, Selection Sort
Sort algorithm | Time complexity | Space complexity | Stability |
---|---|---|---|
Bubble | O(n^2) | O(1) | YES |
Insertion | O(n^2) | O(1) | YES |
Selection | O(n^2) | O(1) | NO |
Quick | O(nlogn) | O(logn) | NO |
Heap | O(nlogn) | O(1) | NO |
Merge | O(nlogn) | O(n) | YES |
Counting | O(n+k) | O(n+k) | YES |
Bucket | O(n+k) | O(n+k) | YES |
Radix | O(dn) | O(n) | YES |
External Sorting
- The sort we talk about is internal sort
- External sorting is required when the data being sorted do not fit into the main memory of a computing device and instead they must reside in the slower external memory
- k-way merge
- Instead of only considering the sorting algorithm, you need to count for the I/O time
What do we need to know
- Some basic ideas on how these sorting algorithms work
- Arrays.sort and Collections.sort
- Comparator and Comparable
Largest Number
Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
Largest Number
How to use sort to decide the largest number?
Example:
If we have 9 and 58. 958 > 589
-> To sort them, we need to concat them and compare which is larger.
-> This can apply to N numbers.
Largest Number
public String largestNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return "";
}
String[] strs = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
strs[i] = String.valueOf(nums[i]);
}
Arrays.sort(strs, new Comparator<String>(){
public int compare(String str1, String str2) {
return (str2 + str1).compareTo(str1 + str2);
}
});
if (strs[0].charAt(0) == '0') {
return "0";
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < strs.length; i++) {
result.append(strs[i]);
}
return result.toString();
}
Largest Number
def largestNumber(self, nums: List[int]) -> str:
if not nums:
return ""
# Convert the integers to strings
strs = list(map(str, nums))
# Sort strings based on custom comparator
strs.sort(key=cmp_to_key(lambda x, y: 1 if x + y < y + x else -1))
# If the largest number is "0", return "0"
if strs[0] == '0':
return "0"
# Join sorted strings to form the largest number
return ''.join(strs)
Best Meeting Point
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
For example, given three people living at (0,0), (0,4), and (2,2): Result is (0,2)
1 - 0 - 0 - 0 - 1
| | | | |
0 - 0 - 0 - 0 - 0
| | | | |
0 - 0 - 1 - 0 - 0
Best Meeting Point
First we consider the one dimension case:
_____A________________B_________
_____A______P_________B_________
_____A________________B____P____
As long as P is in the middle of A and B, the total distance is the same
______A________B________P________C_______D______
The total distance is AD + BC as long as P is in the middle
Best Meeting Point
So For two dimension, since it is Manhattan Distance, we can just take x and y separately
Pair first and last, second and second last ...
If there are 2N points, then P is in the middle of the median two.
If there are 2N+1 points, then P is just the N+1 point
Best Meeting Point
public int minTotalDistance(int[][] grid) {
List<Integer> ipos = new ArrayList<Integer>();
List<Integer> jpos = new ArrayList<Integer>();
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
if(grid[i][j] == 1){
ipos.add(i);
jpos.add(j);
}
}
}
int sum = 0;
Collections.sort(ipos);
Collections.sort(jpos);
int i = 0, j = ipos.size() - 1;
while (i < j) {
sum += ipos.get(j) - ipos.get(i);
sum += jpos.get(j) - jpos.get(i);
i ++;
j --;
}
return sum;
}
Best Meeting Point
def min_total_distance(grid):
ipos = []
jpos = []
# Collect row and column positions of all '1's
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
ipos.append(i)
jpos.append(j)
# Sort the positions to get median-based meeting point
ipos.sort()
jpos.sort()
# Calculate minimum total distance
sum_distance = 0
i, j = 0, len(ipos) - 1
while i < j:
sum_distance += ipos[j] - ipos[i]
sum_distance += jpos[j] - jpos[i]
i += 1
j -= 1
return sum_distance
Merge Intervals
Given a collection of intervals, merge all overlapping intervals.
For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].
Merge Intervals
We need to sort the intervals
Based on what? -> start
Go through all the results and merge them one by one
Merge Intervals
public List<int[]> merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); // Sort intervals
List<int[]> stack = new ArrayList<>();
if (intervals.length == 0) return stack;
for (int[] interval : intervals) {
int l = interval[0];
int r = interval[1];
if (!stack.isEmpty()) {
int[] prev = stack.get(stack.size() - 1);
int prev_l = prev[0];
int prev_r = prev[1];
if (prev_r < l) {
stack.add(new int[] {l, r});
} else {
prev[1] = Math.max(prev_r, r);
}
} else {
stack.add(new int[] {l, r});
}
}
return stack;
}
Merge Intervals
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort()
stack = []
if intervals == []: return stack
for l, r in intervals:
if stack:
prev_l, prev_r = stack[-1]
if prev_r < l:
stack.append([l, r])
else:
stack[-1][1] = max(prev_r, r)
else:
stack.append([l, r])
return stack
Kth Largest Element in an Array
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
private int quickSelect(int[] nums, int start, int end, int target) {
if (start >= end) {
return nums[start];
}
int mid = (start + end) / 2;
int pivot = nums[mid];
int left = start, right = end;
while (left <= right) {
while (left <= right && nums[left] < pivot) {
left++;
}
while (left <= right && nums[right] > pivot) {
right--;
}
if (left <= right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
right--;
}
}
if (target <= right) {
return quickSelect(nums, start, right, target);
} else if (target >= left) {
return quickSelect(nums, left, end, target);
} else {
return nums[target];
}
}
Kth Largest Element in an Array
def findKthLargest(self, nums: List[int], k: int) -> int:
def quickSelect(nums, start, end, target):
if start >= end:
return nums[start]
mid = (start + end) // 2
pivot = nums[mid]
left, right = start, end
while left <= right:
while left <= right and nums[left] < pivot:
left += 1
while left <= right and nums[right] > pivot:
right -= 1
if left <= right:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right -= 1
if target <= right:
return quickSelect(nums, start, right, target)
elif target >= left:
return quickSelect(nums, left, end, target)
else:
return nums[target]
return quickSelect(nums, 0, len(nums) - 1, len(nums) - k)
Sort Colors
Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
You must solve this problem without using the library's sort function.
Example 1:
Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
Example 2:
Input: nums = [2,0,1]
Output: [0,1,2]
Sort Colors
public void sortColors(int[] nums) {
int n = nums.length;
int p0 = 0;
int p2 = n - 1;
int cur = 0;
while (cur <= p2) {
int c = nums[cur];
if (c == 0) {
// Swap nums[cur] and nums[p0]
int temp = nums[cur];
nums[cur] = nums[p0];
nums[p0] = temp;
p0++;
} else if (c == 2) {
// Swap nums[cur] and nums[p2]
int temp = nums[cur];
nums[cur] = nums[p2];
nums[p2] = temp;
p2--;
cur--; // Move cur back to check the swapped element
}
cur++;
}
}
Sort Colors
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
p0 = 0
p2 = n - 1
cur = 0
while cur <= p2:
c = nums[cur]
if c == 0:
nums[cur], nums[p0] = nums[p0], nums[cur]
p0 += 1
elif c == 2:
nums[cur], nums[p2] = nums[p2], nums[cur]
p2 -= 1
cur -= 1
cur += 1
return
Homework
Copy of Copy of [GoValley-Jo] Sort 10
By ZhiTongGuiGu
Copy of Copy of [GoValley-Jo] Sort 10
- 41