710359. K Centers Problem
Hard
K Centers Problem
Slug: k-centers-problem
Difficulty: Hard
Id: 710359
Summary
The K Centers problem is a classic clustering problem where we need to find the optimal set of K centers in a given set of points such that the maximum distance from any point to its nearest center is minimized. This problem involves concepts like greedy algorithms, clustering, and optimization.
Detailed Explanation
The problem can be solved using a combination of greedy algorithm and clustering approach.
Here's a step-by-step breakdown of the solution:
- Initialize K centers: Randomly select K points from the given set of points as the initial centers.
- Cluster assignment: Assign each point to its nearest center.
- Re-centering: Update the positions of the K centers by calculating their new positions based on the assigned points.
- Repeat steps 2-3 until no further changes occur.
The time complexity of this algorithm is O(nklogn) where n is the number of points and k is the number of centers, due to the use of sorting in step 3.
The space complexity is O(n) for storing the points and their assigned centers.
Optimized Solutions
Java
import java.util.*;
public class KCenters {
public static List<Integer> kCenters(int[][] points, int K) {
// Initialize K centers
Random rand = new Random();
List<Integer[]> centers = new ArrayList<>();
for (int i = 0; i < K; i++) {
centers.add(new Integer[]{rand.nextInt(100), rand.nextInt(100)});
}
while (true) {
// Cluster assignment
Map<Integer, Integer> clusterAssignment = new HashMap<>();
for (int[] point : points) {
int minDistance = Integer.MAX_VALUE;
Integer nearestCenterIndex = null;
for (int i = 0; i < K; i++) {
int distance = distance(point, centers.get(i));
if (distance < minDistance) {
minDistance = distance;
nearestCenterIndex = i;
}
}
clusterAssignment.put(Arrays.hashCode(point), nearestCenterIndex);
}
// Re-centering
List<Integer[]> newCenters = new ArrayList<>();
for (int i = 0; i < K; i++) {
int[] centerPoint = null;
int sumX = 0, sumY = 0;
int count = 0;
for (Map.Entry<Integer, Integer> entry : clusterAssignment.entrySet()) {
if (entry.getValue().equals(i)) {
int[] point = points[entry.getKey()];
sumX += point[0];
sumY += point[1];
count++;
}
}
centerPoint = new int[]{sumX / count, sumY / count};
newCenters.add(centerPoint);
}
centers = newCenters;
// Check for convergence
boolean converged = true;
for (int i = 0; i < K; i++) {
if (!Arrays.equals(centers.get(i), newCenters.get(i))) {
converged = false;
break;
}
}
if (converged) {
break;
}
}
return centers.stream().mapToInt(Integer[]::intValue).toArray();
}
public static int distance(int[] p1, int[] p2) {
return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
}
}