https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/
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);
}
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)
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
}
}
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
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?
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.
In-place: Bubble Sort, Insertion Sort, Selection Sort, QuickSort, HeapSort
Out-of place: Merge Sort, Counting Sort, Bucket Sort, Radix Sort
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 |
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.
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.
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();
}
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)
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
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
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
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;
}
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
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].
We need to sort the intervals
Based on what? -> start
Go through all the results and merge them one by one
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;
}
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
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];
}
}
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)
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]
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++;
}
}
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