Problem: Minimum Area Rectangle II

You are given an array of points in the X-Y plane `points` where `points[i] =
[xi, yi]`.

Return the minimum area of any rectangle formed from these points, with sides
not necessarily parallel to the X and Y axes. If there is not any such
rectangle, return `0`.

Answers within `10-5` of the actual answer will be accepted.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator
from math import sqrt

class Solution:
  def minAreaFreeRect(self, points: List[List[int]]) -> float:
    ans = math.inf
    centerToPoints = collections.defaultdict(list)

    for ax, ay in points:
      for bx, by in points:
        center = ((ax + bx) / 2, (ay + by) / 2)
        centerToPoints[center].append((ax, ay, bx, by))

    def dist(px: int, py: int, qx: int, qy: int) -> float:
      return (px - qx)**2 + (py - qy)**2

    for points in centerToPoints.values():
      for ax, ay, _, _ in points:
        for cx, cy, dx, dy in points:
          if (cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0:
            squaredArea = dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy)
            if squaredArea > 0:
              ans = min(ans, squaredArea)

    return 0 if ans == math.inf else sqrt(ans)


Java solution:
class Solution {
  public double minAreaFreeRect(int[][] points) {
    long ans = Long.MAX_VALUE;
    // For each A, B pair points, {hash(A, B): (ax, ay, bx, by)}.
    Map<Integer, List<int[]>> centerToPoints = new HashMap<>();

    for (int[] A : points)
      for (int[] B : points) {
        int center = hash(A, B);
        if (centerToPoints.get(center) == null)
          centerToPoints.put(center, new ArrayList<>());
        centerToPoints.get(center).add(new int[] {A[0], A[1], B[0], B[1]});
      }

    // For all pair points "that share the same center".
    for (List<int[]> pointPairs : centerToPoints.values())
      for (int[] ab : pointPairs)
        for (int[] cd : pointPairs) {
          final int ax = ab[0], ay = ab[1];
          final int cx = cd[0], cy = cd[1];
          final int dx = cd[2], dy = cd[3];
          // AC is perpendicular to AD.
          // AC dot AD = (cx - ax, cy - ay) dot (dx - ax, dy - ay) == 0.
          if ((cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0) {
            final long squaredArea = dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy);
            if (squaredArea > 0)
              ans = Math.min(ans, squaredArea);
          }
        }

    return ans == Long.MAX_VALUE ? 0 : Math.sqrt(ans);
  }

  private int hash(int[] p, int[] q) {
    return ((p[0] + q[0]) << 16) + (p[1] + q[1]);
  }

  private long dist(long px, long py, long qx, long qy) {
    return (px - qx) * (px - qx) + (py - qy) * (py - qy);
  }
}


C++ solution:
class Solution {
 public:
  double minAreaFreeRect(vector<vector<int>>& points) {
    long ans = LONG_MAX;
    // For each A, B pair points, {hash(A, B): (ax, ay, bx, by)}.
    unordered_map<int, vector<tuple<int, int, int, int>>> centerToPoints;

    for (const vector<int>& A : points)
      for (const vector<int>& B : points) {
        const int center = hash(A, B);
        centerToPoints[center].emplace_back(A[0], A[1], B[0], B[1]);
      }

    // For all pair points "that share the same center".
    for (const auto& [_, points] : centerToPoints)
      for (const auto& [ax, ay, bx, by] : points)
        for (const auto& [cx, cy, dx, dy] : points)
          // AC is perpendicular to AD.
          // AC dot AD = (cx - ax, cy - ay) dot (dx - ax, dy - ay) == 0.
          if ((cx - ax) * (dx - ax) + (cy - ay) * (dy - ay) == 0) {
            const long squaredArea =
                dist(ax, ay, cx, cy) * dist(ax, ay, dx, dy);
            if (squaredArea > 0)
              ans = min(ans, squaredArea);
          }

    return ans == LONG_MAX ? 0 : sqrt(ans);
  }

 private:
  int hash(const vector<int>& p, const vector<int>& q) {
    return ((long)(p[0] + q[0]) << 16) + (p[1] + q[1]);
  }

  long dist(int px, int py, int qx, int qy) {
    return (px - qx) * (px - qx) + (py - qy) * (py - qy);
  }
};