refactor: FindKthNumber (#5374)

This commit is contained in:
Alex Klymenko 2024-08-24 10:53:35 +02:00 committed by GitHub
parent 84fb717509
commit 4e72056527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 103 additions and 56 deletions

View File

@ -1,10 +1,9 @@
package com.thealgorithms.maths; package com.thealgorithms.maths;
import java.util.Arrays;
import java.util.Random; import java.util.Random;
/** /**
* use quick sort algorithm to get kth largest or kth smallest element in given array * Use a quicksort-based approach to identify the k-th largest or k-th max element within the provided array.
*/ */
public final class FindKthNumber { public final class FindKthNumber {
private FindKthNumber() { private FindKthNumber() {
@ -12,66 +11,55 @@ public final class FindKthNumber {
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
public static void main(String[] args) { public static int findKthMax(int[] array, int k) {
/* generate an array with random size and random elements */ if (k <= 0 || k > array.length) {
int[] nums = generateArray(100); throw new IllegalArgumentException("k must be between 1 and the size of the array");
/* get 3th largest element */
int kth = 3;
int kthMaxIndex = nums.length - kth;
int targetMax = findKthMax(nums, kthMaxIndex);
/* get 3th smallest element */
int kthMinIndex = kth - 1;
int targetMin = findKthMax(nums, kthMinIndex);
Arrays.sort(nums);
assert nums[kthMaxIndex] == targetMax;
assert nums[kthMinIndex] == targetMin;
}
private static int[] generateArray(int capacity) {
int size = RANDOM.nextInt(capacity) + 1;
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = RANDOM.nextInt() % 100;
} }
return array;
// Convert k-th largest to index for QuickSelect
return quickSelect(array, 0, array.length - 1, array.length - k);
} }
private static int findKthMax(int[] nums, int k) { private static int quickSelect(int[] array, int left, int right, int kSmallest) {
int start = 0; if (left == right) {
int end = nums.length; return array[left];
while (start < end) { }
int pivot = partition(nums, start, end);
if (k == pivot) { // Randomly select a pivot index
return nums[pivot]; int pivotIndex = left + RANDOM.nextInt(right - left + 1);
} else if (k > pivot) { pivotIndex = partition(array, left, right, pivotIndex);
start = pivot + 1;
} else { if (kSmallest == pivotIndex) {
end = pivot; return array[kSmallest];
} else if (kSmallest < pivotIndex) {
return quickSelect(array, left, pivotIndex - 1, kSmallest);
} else {
return quickSelect(array, pivotIndex + 1, right, kSmallest);
}
}
private static int partition(int[] array, int left, int right, int pivotIndex) {
int pivotValue = array[pivotIndex];
// Move pivot to end
swap(array, pivotIndex, right);
int storeIndex = left;
// Move all smaller elements to the left
for (int i = left; i < right; i++) {
if (array[i] < pivotValue) {
swap(array, storeIndex, i);
storeIndex++;
} }
} }
return -1;
// Move pivot to its final place
swap(array, storeIndex, right);
return storeIndex;
} }
private static int partition(int[] nums, int start, int end) { private static void swap(int[] array, int i, int j) {
int pivot = nums[start]; int temp = array[i];
int j = start; array[i] = array[j];
for (int i = start + 1; i < end; i++) { array[j] = temp;
if (nums[i] < pivot) {
j++;
swap(nums, i, j);
}
}
swap(nums, start, j);
return j;
}
private static void swap(int[] nums, int a, int b) {
int tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
} }
} }

View File

@ -0,0 +1,59 @@
package com.thealgorithms.maths;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import java.util.Random;
import org.junit.jupiter.api.Test;
public class FindKthNumberTest {
@Test
public void testFindKthMaxTypicalCases() {
int[] array1 = {3, 2, 1, 4, 5};
assertEquals(3, FindKthNumber.findKthMax(array1, 3));
assertEquals(4, FindKthNumber.findKthMax(array1, 2));
assertEquals(5, FindKthNumber.findKthMax(array1, 1));
int[] array2 = {7, 5, 8, 2, 1, 6};
assertEquals(5, FindKthNumber.findKthMax(array2, 4));
assertEquals(6, FindKthNumber.findKthMax(array2, 3));
assertEquals(8, FindKthNumber.findKthMax(array2, 1));
}
@Test
public void testFindKthMaxEdgeCases() {
int[] array1 = {1};
assertEquals(1, FindKthNumber.findKthMax(array1, 1));
int[] array2 = {5, 3};
assertEquals(5, FindKthNumber.findKthMax(array2, 1));
assertEquals(3, FindKthNumber.findKthMax(array2, 2));
}
@Test
public void testFindKthMaxInvalidK() {
int[] array = {1, 2, 3, 4, 5};
assertThrows(IllegalArgumentException.class, () -> FindKthNumber.findKthMax(array, 0));
assertThrows(IllegalArgumentException.class, () -> FindKthNumber.findKthMax(array, 6));
}
@Test
public void testFindKthMaxLargeArray() {
int[] array = generateArray(1000);
int k = new Random().nextInt(array.length);
int result = FindKthNumber.findKthMax(array, k);
Arrays.sort(array);
assertEquals(array[array.length - k], result);
}
public static int[] generateArray(int capacity) {
int size = new Random().nextInt(capacity) + 1;
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = new Random().nextInt(100); // Ensure positive values for testing
}
return array;
}
}