Below is the implementation of the proximity point finder:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154/** * Sorting Approach * Time Complexity: O(n log n) - Dominated by the sorting operation * Space Complexity: O(n) - For storing the distances and sorted points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestSorting(points, k) { // Sort points by distance to origin return points.sort((a, b) => { return (a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1]); }).slice(0, k);} /** * Max Heap Approach * Time Complexity: O(n log k) - Where n is the number of points * Space Complexity: O(k) - For storing the heap of size k * * Note: JavaScript doesn't have a built-in heap, so we'll implement a simple max heap * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestMaxHeap(points, k) { // Create a max heap of size k const heap = []; // Helper function to maintain heap property const heapify = (i) => { const left = 2 * i + 1; const right = 2 * i + 2; let largest = i; if (left < heap.length && heap[left][0] > heap[largest][0]) { largest = left; } if (right < heap.length && heap[right][0] > heap[largest][0]) { largest = right; } if (largest !== i) { [heap[i], heap[largest]] = [heap[largest], heap[i]]; heapify(largest); } }; // Add point to heap const addToHeap = (distance, point) => { heap.push([distance, point]); let i = heap.length - 1; let parent = Math.floor((i - 1) / 2); while (i > 0 && heap[i][0] > heap[parent][0]) { [heap[i], heap[parent]] = [heap[parent], heap[i]]; i = parent; parent = Math.floor((i - 1) / 2); } }; // Remove top element from heap const pollFromHeap = () => { const top = heap[0]; heap[0] = heap[heap.length - 1]; heap.pop(); heapify(0); return top; }; // Process all points for (const point of points) { const distance = point[0] * point[0] + point[1] * point[1]; addToHeap(distance, point); if (heap.length > k) { pollFromHeap(); } } // Extract points from heap const result = []; while (heap.length > 0) { result.push(pollFromHeap()[1]); } return result;} /** * QuickSelect Approach * Time Complexity: O(n) average, O(n²) worst case * Space Complexity: O(n) - For storing the distances and points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestQuickSelect(points, k) { // Calculate squared distances const distances = points.map(point => { const distance = point[0] * point[0] + point[1] * point[1]; return [distance, point]; }); // QuickSelect algorithm const quickSelect = (left, right) => { if (left >= right) return; // Choose pivot (rightmost element) const pivot = distances[right][0]; let i = left; // Partition around pivot for (let j = left; j < right; j++) { if (distances[j][0] <= pivot) { [distances[i], distances[j]] = [distances[j], distances[i]]; i++; } } // Place pivot in its final position [distances[i], distances[right]] = [distances[right], distances[i]]; // If pivot is at position k-1, we've found our answer if (i === k - 1) { return; } else if (i < k - 1) { // If pivot is before position k-1, search in the right half quickSelect(i + 1, right); } else { // If pivot is after position k-1, search in the left half quickSelect(left, i - 1); } }; // Apply QuickSelect quickSelect(0, distances.length - 1); // Return k closest points return distances.slice(0, k).map(item => item[1]);} // Test casesconst points1 = [[1, 3], [-2, 2]];const k1 = 1;console.log(kClosestSorting(points1, k1)); // [[-2, 2]] const points2 = [[3, 3], [5, -1], [-2, 4]];const k2 = 2;console.log(kClosestSorting(points2, k2)); // [[3, 3], [-2, 4]] or [[-2, 4], [3, 3]]
Let's break down the implementation:
Implement the proximity point finder solution in different programming languages.
Below is the implementation of the proximity point finder in different programming languages. Select a language tab to view the corresponding code.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154/** * Sorting Approach * Time Complexity: O(n log n) - Dominated by the sorting operation * Space Complexity: O(n) - For storing the distances and sorted points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestSorting(points, k) { // Sort points by distance to origin return points.sort((a, b) => { return (a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1]); }).slice(0, k);} /** * Max Heap Approach * Time Complexity: O(n log k) - Where n is the number of points * Space Complexity: O(k) - For storing the heap of size k * * Note: JavaScript doesn't have a built-in heap, so we'll implement a simple max heap * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestMaxHeap(points, k) { // Create a max heap of size k const heap = []; // Helper function to maintain heap property const heapify = (i) => { const left = 2 * i + 1; const right = 2 * i + 2; let largest = i; if (left < heap.length && heap[left][0] > heap[largest][0]) { largest = left; } if (right < heap.length && heap[right][0] > heap[largest][0]) { largest = right; } if (largest !== i) { [heap[i], heap[largest]] = [heap[largest], heap[i]]; heapify(largest); } }; // Add point to heap const addToHeap = (distance, point) => { heap.push([distance, point]); let i = heap.length - 1; let parent = Math.floor((i - 1) / 2); while (i > 0 && heap[i][0] > heap[parent][0]) { [heap[i], heap[parent]] = [heap[parent], heap[i]]; i = parent; parent = Math.floor((i - 1) / 2); } }; // Remove top element from heap const pollFromHeap = () => { const top = heap[0]; heap[0] = heap[heap.length - 1]; heap.pop(); heapify(0); return top; }; // Process all points for (const point of points) { const distance = point[0] * point[0] + point[1] * point[1]; addToHeap(distance, point); if (heap.length > k) { pollFromHeap(); } } // Extract points from heap const result = []; while (heap.length > 0) { result.push(pollFromHeap()[1]); } return result;} /** * QuickSelect Approach * Time Complexity: O(n) average, O(n²) worst case * Space Complexity: O(n) - For storing the distances and points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestQuickSelect(points, k) { // Calculate squared distances const distances = points.map(point => { const distance = point[0] * point[0] + point[1] * point[1]; return [distance, point]; }); // QuickSelect algorithm const quickSelect = (left, right) => { if (left >= right) return; // Choose pivot (rightmost element) const pivot = distances[right][0]; let i = left; // Partition around pivot for (let j = left; j < right; j++) { if (distances[j][0] <= pivot) { [distances[i], distances[j]] = [distances[j], distances[i]]; i++; } } // Place pivot in its final position [distances[i], distances[right]] = [distances[right], distances[i]]; // If pivot is at position k-1, we've found our answer if (i === k - 1) { return; } else if (i < k - 1) { // If pivot is before position k-1, search in the right half quickSelect(i + 1, right); } else { // If pivot is after position k-1, search in the left half quickSelect(left, i - 1); } }; // Apply QuickSelect quickSelect(0, distances.length - 1); // Return k closest points return distances.slice(0, k).map(item => item[1]);} // Test casesconst points1 = [[1, 3], [-2, 2]];const k1 = 1;console.log(kClosestSorting(points1, k1)); // [[-2, 2]] const points2 = [[3, 3], [5, -1], [-2, 4]];const k2 = 2;console.log(kClosestSorting(points2, k2)); // [[3, 3], [-2, 4]] or [[-2, 4], [3, 3]]
First, understand that we need to find the k closest points to the origin (0, 0) based on Euclidean distance.
For each point (x, y), calculate its squared distance from the origin: x² + y². We use squared distance to avoid floating-point calculations.
Decide which approach to use: sorting all points, using a max heap of size k, or using the QuickSelect algorithm.
Implement the chosen approach, paying attention to the distance calculation and the selection of the k closest points.
Consider edge cases such as k = 1, k = points.length, or when multiple points have the same distance from the origin.
Consider optimizations such as using QuickSelect for O(n) average time complexity instead of sorting for O(n log n) time complexity.
Verify the solution with the provided examples and additional test cases.
Modify the code to implement an alternative approach and test it with the same examples.
Implement a function that solves the proximity point finder problem using a different approach than shown above.
If k = 1, we need to find the single closest point to the origin.
If k equals the number of points, we return all points sorted by their distances from the origin.
If multiple points have the same distance from the origin, any of them can be included in the result as long as we return exactly k points.
If some points are at the origin (0, 0), they have a distance of 0 and should be included first in the result.
Below is the implementation of the proximity point finder:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154/** * Sorting Approach * Time Complexity: O(n log n) - Dominated by the sorting operation * Space Complexity: O(n) - For storing the distances and sorted points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestSorting(points, k) { // Sort points by distance to origin return points.sort((a, b) => { return (a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1]); }).slice(0, k);} /** * Max Heap Approach * Time Complexity: O(n log k) - Where n is the number of points * Space Complexity: O(k) - For storing the heap of size k * * Note: JavaScript doesn't have a built-in heap, so we'll implement a simple max heap * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestMaxHeap(points, k) { // Create a max heap of size k const heap = []; // Helper function to maintain heap property const heapify = (i) => { const left = 2 * i + 1; const right = 2 * i + 2; let largest = i; if (left < heap.length && heap[left][0] > heap[largest][0]) { largest = left; } if (right < heap.length && heap[right][0] > heap[largest][0]) { largest = right; } if (largest !== i) { [heap[i], heap[largest]] = [heap[largest], heap[i]]; heapify(largest); } }; // Add point to heap const addToHeap = (distance, point) => { heap.push([distance, point]); let i = heap.length - 1; let parent = Math.floor((i - 1) / 2); while (i > 0 && heap[i][0] > heap[parent][0]) { [heap[i], heap[parent]] = [heap[parent], heap[i]]; i = parent; parent = Math.floor((i - 1) / 2); } }; // Remove top element from heap const pollFromHeap = () => { const top = heap[0]; heap[0] = heap[heap.length - 1]; heap.pop(); heapify(0); return top; }; // Process all points for (const point of points) { const distance = point[0] * point[0] + point[1] * point[1]; addToHeap(distance, point); if (heap.length > k) { pollFromHeap(); } } // Extract points from heap const result = []; while (heap.length > 0) { result.push(pollFromHeap()[1]); } return result;} /** * QuickSelect Approach * Time Complexity: O(n) average, O(n²) worst case * Space Complexity: O(n) - For storing the distances and points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestQuickSelect(points, k) { // Calculate squared distances const distances = points.map(point => { const distance = point[0] * point[0] + point[1] * point[1]; return [distance, point]; }); // QuickSelect algorithm const quickSelect = (left, right) => { if (left >= right) return; // Choose pivot (rightmost element) const pivot = distances[right][0]; let i = left; // Partition around pivot for (let j = left; j < right; j++) { if (distances[j][0] <= pivot) { [distances[i], distances[j]] = [distances[j], distances[i]]; i++; } } // Place pivot in its final position [distances[i], distances[right]] = [distances[right], distances[i]]; // If pivot is at position k-1, we've found our answer if (i === k - 1) { return; } else if (i < k - 1) { // If pivot is before position k-1, search in the right half quickSelect(i + 1, right); } else { // If pivot is after position k-1, search in the left half quickSelect(left, i - 1); } }; // Apply QuickSelect quickSelect(0, distances.length - 1); // Return k closest points return distances.slice(0, k).map(item => item[1]);} // Test casesconst points1 = [[1, 3], [-2, 2]];const k1 = 1;console.log(kClosestSorting(points1, k1)); // [[-2, 2]] const points2 = [[3, 3], [5, -1], [-2, 4]];const k2 = 2;console.log(kClosestSorting(points2, k2)); // [[3, 3], [-2, 4]] or [[-2, 4], [3, 3]]
Let's break down the implementation:
Implement the proximity point finder solution in different programming languages.
Below is the implementation of the proximity point finder in different programming languages. Select a language tab to view the corresponding code.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154/** * Sorting Approach * Time Complexity: O(n log n) - Dominated by the sorting operation * Space Complexity: O(n) - For storing the distances and sorted points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestSorting(points, k) { // Sort points by distance to origin return points.sort((a, b) => { return (a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1]); }).slice(0, k);} /** * Max Heap Approach * Time Complexity: O(n log k) - Where n is the number of points * Space Complexity: O(k) - For storing the heap of size k * * Note: JavaScript doesn't have a built-in heap, so we'll implement a simple max heap * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestMaxHeap(points, k) { // Create a max heap of size k const heap = []; // Helper function to maintain heap property const heapify = (i) => { const left = 2 * i + 1; const right = 2 * i + 2; let largest = i; if (left < heap.length && heap[left][0] > heap[largest][0]) { largest = left; } if (right < heap.length && heap[right][0] > heap[largest][0]) { largest = right; } if (largest !== i) { [heap[i], heap[largest]] = [heap[largest], heap[i]]; heapify(largest); } }; // Add point to heap const addToHeap = (distance, point) => { heap.push([distance, point]); let i = heap.length - 1; let parent = Math.floor((i - 1) / 2); while (i > 0 && heap[i][0] > heap[parent][0]) { [heap[i], heap[parent]] = [heap[parent], heap[i]]; i = parent; parent = Math.floor((i - 1) / 2); } }; // Remove top element from heap const pollFromHeap = () => { const top = heap[0]; heap[0] = heap[heap.length - 1]; heap.pop(); heapify(0); return top; }; // Process all points for (const point of points) { const distance = point[0] * point[0] + point[1] * point[1]; addToHeap(distance, point); if (heap.length > k) { pollFromHeap(); } } // Extract points from heap const result = []; while (heap.length > 0) { result.push(pollFromHeap()[1]); } return result;} /** * QuickSelect Approach * Time Complexity: O(n) average, O(n²) worst case * Space Complexity: O(n) - For storing the distances and points * * @param {number[][]} points - Array of points [x, y] * @param {number} k - Number of closest points to return * @return {number[][]} - k closest points to the origin */function kClosestQuickSelect(points, k) { // Calculate squared distances const distances = points.map(point => { const distance = point[0] * point[0] + point[1] * point[1]; return [distance, point]; }); // QuickSelect algorithm const quickSelect = (left, right) => { if (left >= right) return; // Choose pivot (rightmost element) const pivot = distances[right][0]; let i = left; // Partition around pivot for (let j = left; j < right; j++) { if (distances[j][0] <= pivot) { [distances[i], distances[j]] = [distances[j], distances[i]]; i++; } } // Place pivot in its final position [distances[i], distances[right]] = [distances[right], distances[i]]; // If pivot is at position k-1, we've found our answer if (i === k - 1) { return; } else if (i < k - 1) { // If pivot is before position k-1, search in the right half quickSelect(i + 1, right); } else { // If pivot is after position k-1, search in the left half quickSelect(left, i - 1); } }; // Apply QuickSelect quickSelect(0, distances.length - 1); // Return k closest points return distances.slice(0, k).map(item => item[1]);} // Test casesconst points1 = [[1, 3], [-2, 2]];const k1 = 1;console.log(kClosestSorting(points1, k1)); // [[-2, 2]] const points2 = [[3, 3], [5, -1], [-2, 4]];const k2 = 2;console.log(kClosestSorting(points2, k2)); // [[3, 3], [-2, 4]] or [[-2, 4], [3, 3]]
First, understand that we need to find the k closest points to the origin (0, 0) based on Euclidean distance.
For each point (x, y), calculate its squared distance from the origin: x² + y². We use squared distance to avoid floating-point calculations.
Decide which approach to use: sorting all points, using a max heap of size k, or using the QuickSelect algorithm.
Implement the chosen approach, paying attention to the distance calculation and the selection of the k closest points.
Consider edge cases such as k = 1, k = points.length, or when multiple points have the same distance from the origin.
Consider optimizations such as using QuickSelect for O(n) average time complexity instead of sorting for O(n log n) time complexity.
Verify the solution with the provided examples and additional test cases.
Modify the code to implement an alternative approach and test it with the same examples.
Implement a function that solves the proximity point finder problem using a different approach than shown above.
If k = 1, we need to find the single closest point to the origin.
If k equals the number of points, we return all points sorted by their distances from the origin.
If multiple points have the same distance from the origin, any of them can be included in the result as long as we return exactly k points.
If some points are at the origin (0, 0), they have a distance of 0 and should be included first in the result.