Post

Geometry

Theorem

Triangle area using coordinates

\[ T={\frac {1}{2}}{\big |}(x_{A}-x_{C})(y_{B}-y_{A})-(x_{A}-x_{B})(y_{C}-y_{A}){\big |} \]

Triangle inequality

In a normed vector space \(V\), one of the defining properties of the norm is the triangle inequality:

\[|x+y|\leq |x|+|y|\quad \forall \,x,y\in V\]

Escape The Ghosts

1
2
3
4
5
6
7
8
9
10
public boolean escapeGhosts(int[][] ghosts, int[] target) {
    // Manhattan distance
    int d = Math.abs(target[0]) + Math.abs(target[1]);
    for (int[] g : ghosts) {
        if (Math.abs(g[0] - target[0]) + Math.abs(g[1] - target[1]) <= d) {
            return false;
        }
    }
    return true;
}

Graham scan

For three points \(P_{1}=(x_{1},y_{1})\), \(P_{2}=(x_{2},y_{2})\) and \(P_{3}=(x_{3},y_{3})\), compute the z-coordinate of the cross product of the two vectors \(\overrightarrow {P_{1}P_{2}}\) and \(\overrightarrow {P_{1}P_{3}}\), which is given by the expression \((x_{2}-x_{1})(y_{3}-y_{1})-(y_{2}-y_{1})(x_{3}-x_{1})\).

Convex Polygon

Overlapping

Circle and Rectangle Overlapping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
    // finds the closest point of the rectangle to the center.
    // if the center is in the rectangle, the center itself is the point
    int x = closest(x_center, x1, x2);
    int y = closest(y_center, y1, y2);

    int dx = x_center - x;
    int dy = y_center - y;

    return dx * dx + dy * dy <= radius * radius;
}

private int closest(int value, int min, int max) {
    return Math.max(min, Math.min(max, value));
}

Area

Minimum Area Rectangle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public int minAreaRect(int[][] points) {
    Map<Integer, Set<Integer>> map = new HashMap<>();
    for (int[] p : points) {
        map.computeIfAbsent(p[0], k -> new HashSet<>()).add(p[1]);
    }

    int min = Integer.MAX_VALUE;
    for (int i = 0; i < points.length; i++) {
        for (int j = 0; j < i; j++) {
            // diagnoal opposite points
            int[] p1 = points[i], p2 = points[j];
            // skips same x or y
            if (p1[0] == p2[0] || p1[1] == p2[1]) {
                continue;
            }

            int area = Math.abs(p1[0] - p2[0]) * Math.abs(p1[1] - p2[1]);
            if (area > min) {
                continue;
            }

            // computes diagonal points only
            // confirms the other two points exist in the set
            if (map.get(p1[0]).contains(p2[1]) && map.get(p2[0]).contains(p1[1])) {
                min = area;
            }
        }
    }
    return min == Integer.MAX_VALUE ? 0 : min;
}

Minimum Area Rectangle II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public int minAreaRect(int[][] points) {
    Map<Integer, Set<Integer>> map = new HashMap<>();
    for (int[] p : points) {
        map.computeIfAbsent(p[0], k -> new HashSet<>()).add(p[1]);
    }

    int min = Integer.MAX_VALUE;
    for (int i = 0; i < points.length; i++) {
        for (int j = 0; j < i; j++) {
            int[] p1 = points[i], p2 = points[j];
            // skips same x or y
            if (p1[0] == p2[0] || p1[1] == p2[1]) {
                continue;
            }

            int area = Math.abs(p1[0] - p2[0]) * Math.abs(p1[1] - p2[1]);
            if (area > min) {
                continue;
            }

            // computes diagonal points only
            // confirms the other two points exist in the set
            if (map.get(p1[0]).contains(p2[1]) && map.get(p2[0]).contains(p1[1])) {
                min = area;
            }
        }
    }
    return min == Integer.MAX_VALUE ? 0 : min;
}

Dihedral Group

Dihedral group: the group of symmetries of a regular polygon, which includes rotations and reflections.

Number of Distinct Islands II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
private static final int[][] DIRECTIONS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
private static final int[][] TRANSFORMATIONS = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

private int[][] grid;
private int m, n;
private boolean[][] visited;

public int numDistinctIslands2(int[][] grid) {
    this.grid = grid;
    this.m = grid.length;
    this.n = grid[0].length;
    this.visited = new boolean[m][n];

    Set<String> islands = new HashSet<>();
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (grid[i][j] == 1 && !visited[i][j]) {
                List<int[]> cells = new ArrayList<>();
                dfs(i, j, cells);
                islands.add(norm(cells));
            }
        }
    }
    return islands.size();
}

private void dfs(int i, int j, List<int[]> cells) {
    if (i < 0 || i == m || j < 0 || j == n || grid[i][j] == 0 || visited[i][j]) {
        return;
    }

    visited[i][j] = true;
    cells.add(new int[]{i, j});

    for (int[] d : DIRECTIONS) {
        dfs(i + d[0], j + d[1], cells);
    }
}

private String norm(List<int[]>cells) {
    List<String> forms = new ArrayList<>();
    // generates 8 different transformations:
    //  (x, y), (x, -y), (-x, y), (-x, -y)
    //  (y, x), (-y, x), (y, -x), (-y, -x)
    for (int[] t : TRANSFORMATIONS) {
        List<int[]> list1 = new ArrayList<>(), list2 = new ArrayList<>();
        for (int[] c : cells) {
            list1.add(new int[]{c[0] * t[0], c[1] * t[1]});
            list2.add(new int[]{c[1] * t[1], c[0] * t[0]});
        }
        forms.add(getKey(list1));
        forms.add(getKey(list2));
    }

    // sorts the keys and uses the first one as the representative
    Collections.sort(forms);
    return forms.get(0);
}

private String getKey(List<int[]> cells) {
    Collections.sort(cells, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);

    StringBuilder sb = new StringBuilder();
    for (int[] c : cells) {
        // (x - x0, y - y0)
        sb.append((c[0] - cells.get(0)[0]) + "#" + (c[1] - cells.get(0)[1]) + "#");
    }
    return sb.toString();
}

Distance

For a real number \(p \ge 1\), the \(p\)-norm or \(L^{p}\)-norm of \(x\) is defined by:

\[\lVert x \rVert_{p}=(|x_{1}|^{p}+|x_{2}|^{p}+\dots +|x_{n}|^{p})^{1/p}\]

Taxicab Distance

Taxicab distance = Manhattan distance: \(L^1\)-norm

Maximum of Absolute Value Expression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public int maxAbsValExpr(int[] arr1, int[] arr2) {
    int max = 0, n = arr1.length;
    int[] coefficients = {-1, 1};

    // |x[i] - x[j]| + |y[i] - y[j]| + |i - j| = f(j) - f(i)
    //   where f(i) = p * x[i] + q * y[i] + i
    //   with p = 1 or -1, q = 1 or -1
    for (int p : coefficients) {
        for (int q : coefficients) {
            // origin point
            int origin = p * arr1[0] + q * arr2[0] + 0;
            // computes the Manhattan distance to the origin point
            for (int i = 1; i < n; i++) {
                int value = p * arr1[i] + q * arr2[i] + i;
                max = Math.max(max, value - origin);
                origin = Math.min(origin, value);
            }
        }
    }
    return max;
}

Minimize Manhattan Distances

Maximum Manhattan Distance

\[\max_{i,j}Manhattan(P_i,P_j) = \max_{i,j}(\max(|s_i - s_j|,|d_i - d_j|))\]

Euclidean Distance

Euclidean distance: \(L^2\)

Chebyshev Distance

Chebyshev distance = chessboard distance: \(L^{\infty}\)

Determine if a Cell Is Reachable at a Given Time

1
2
3
4
5
6
7
8
9
10
11
bool isReachableAtTime(int sx, int sy, int fx, int fy, int t) {
    int dx = abs(sx - fx), dy = abs(sy - fy);
    if (dx == 0 && dy == 0 && t == 1) {
        return false;
    }

    // Chebyshev distance
    // Move diagonally for min(dx, dy)
    // Then go along the longer side
    return min(dx, dy) + abs(dx - dy) <= t;
}

Geometric Median

Geometric median: \(L^1\) estimator.

\[{\underset {y\in \mathbb {R} ^{n}}{\operatorname {arg\,min} }}\sum _{i=1}^{m}\left\|x_{i}-y\right\|_{2}\]

Weiszfeld’s algorithm

\[y_{i+1}=(\sum_{j=1}^{m}{\frac{x_{j}}{\|x_{j}-y_{i}\|}})/(\sum_{j=1}^{m}{\frac{1}{\|x_{j}-y_{i}\|}})\]

Median

One-dimensional median is a special case of geometric median. It is the point about which the mean absolute deviation is minimized.

Mean absolute deviation of a set \(\{x_1,x_2,\ldots,x_n\}\):

\[\frac{1}{n}\sum _{i=1}^{n}|x_{i}-m(X)|\]

Where \(m(X)\) is a measure of central tendency.

  • Mean minimizes total distance for Euclidean distance:
  • Mode minimizes distance for indicator function

Best Meeting Point

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public int minTotalDistance(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    List<Integer> x = new ArrayList<>(), y = new ArrayList<>();
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (grid[i][j] == 1) {
                x.add(i);
            }
        }
    }
    for (int j = 0; j < n; j++) {
        for (int i = 0; i < m; i ++) {
            if (grid[i][j] == 1) {
                y.add(j);
            }
        }
    }
    return minDistance1D(x) + minDistance1D(y);
}

private int minDistance1D(List<Integer> points) {
    int d = 0, median = points.get(points.size() / 2);
    for (int p : points) {
        d += Math.abs(p - median);
    }
    return d;
}

Apply Operations to Maximize Frequency Score

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nt maxFrequencyScore(vector<int>& nums, long long k) {
    ranges::sort(nums);

    int i = 0, j = 0;
    while (j < nums.size()) {
        // Median minimizes the sum of absolute deviation.
        // nums[(i + j++) / 2] equals the median before j moves in.
        // e.g. odd-size window
        //    i = 0, j = 3, window = [0,1,2]
        //    old median = 1
        //    new median = nums[(0 + 3) / 2] = 1
        // e.g. even-size window
        //    i = 0, j = 2, window = [0,1]
        //    old median = 0 or 1
        //    new median = nums[(0 + 2) / 2] = 1
        k -= nums[j] - nums[(i + j++) / 2];
        if (k < 0) {
            // Similarly, nums[(i + j) / 2] equals the median before i moves out.
            k += nums[(i + j) / 2] - nums[i++];
        }
    }
    return j - i;
}

Allocate Mailboxes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private static final int MAX = 100 * 10000;

public int minDistance(int[] houses, int k) {
    int n = houses.length;

    Arrays.sort(houses);

    // finds the median of houses[i] to houses[j]
    // calculates the distance
    int[][] distance = new int[n + 1][n + 1];
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            for (int m = i; m <= j; m++) {
                distance[i][j] += Math.abs(houses[(i + j) / 2] - houses[m]);
            }
        }
    }

    // dp[m][i]: minimum total distance of m mailboxes starting from i-th house
    int[][] dp = new int[k + 1][n + 1];

    // initializes dp table boarders with max
    Arrays.fill(dp[0], MAX);
    for (int i = 1; i <= k; i++) {
        dp[i][n] = MAX;
    }

    // initializes dp[0][n] with 0
    dp[0][n] = 0;

    for (int i = n - 1; i >= 0; i--) {
        for (int m = 1; m <= k; m++) {
            dp[m][i] = Integer.MAX_VALUE;
            for (int j = i; j < n; j++) {
                // houses[i:] is split into two groups:
                // houses[i:j] and houses[(j + 1):]
                dp[m][i] = Math.min(dp[m][i], distance[i][j] + dp[m - 1][j + 1]);
            }
        }
    }

    return dp[k][0];
}

Another way to calculate the distance matrix:

1
2
3
4
5
6
7
8
9
10
11
12
for (int i = n - 1; i >= 0; i--) {
    for (int j = i; j < n; j++) {
        distance[i][j] = houses[j] - houses[i];
        if (i + 1 < n - 1 && j > 0) {
            // from houses[(i + 1):(j - 1)] to houses[i:j]
            // the minimum distance added by the two new endpoints houses[i] and houses[j]
            // equals houses[j] - houses[i]
            // the mailbox can be at any point between the new endpoints
            distance[i][j] += distance[i + 1][j - 1];
        }
    }
}

Median of Two Sorted Arrays

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int m = nums1.size(), n = nums2.size();

    if (m > n) {
        return findMedianSortedArrays(nums2, nums1);
    }

    //       left_part          |        right_part
    // A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
    // B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

    // Binary searches the cut point in nums1
    int low = 0, high = m;
    while (low <= high) {
        // len(left) == len(right)
        // If m + n is even, i + j == m - i + n - j;
        // otherwise, i + j == m - i + n - j + 1.
        // Combines the above two cases:
        // j == (m + n + 1) / 2 - i
        unsigned int i = (low + high) >> 1, j = (m + n + 1) / 2 - i;

        // Values on either side of the cut point of each array
        int nums1Left = i == 0 ? numeric_limits<int>::min() : nums1[i - 1];
        int nums1Right = i == m ? numeric_limits<int>::max() : nums1[i];
        int nums2Left = j == 0 ? numeric_limits<int>::min() : nums2[j - 1];
        int nums2Right = j == n ? numeric_limits<int>::max() : nums2[j];

        // For each array, max(left) <= min(right)
        if (nums1Left > nums2Right) {
            high = i - 1;
        } else if (nums2Left > nums1Right) {
            low = i + 1;
        } else {
            int maxLeft = max(nums1Left, nums2Left);
            int minRight = min(nums1Right, nums2Right);
            return (m + n) % 2 ? maxLeft : ((maxLeft + minRight) / 2.0);
        }
    }
    return -1;
}

Circle

Smallest Circle Problem

Smallest-circle problem: computing the smallest circle that contains all of a given set of points in the Euclidean plane.

Circum Circle Cartesian equation:

\[{\begin{aligned} S_{x}&={\frac {1}{2}}\det {\begin{bmatrix}|\mathbf {A} |^{2}&A_{y}&1\\|\mathbf {B} |^{2}&B_{y}&1\\|\mathbf {C} |^{2}&C_{y}&1\end{bmatrix}},\\[5pt] S_{y}&={\frac {1}{2}}\det {\begin{bmatrix}A_{x}&|\mathbf {A} |^{2}&1\\B_{x}&|\mathbf {B} |^{2}&1\\C_{x}&|\mathbf {C} |^{2}&1\end{bmatrix}},\\[5pt] a&=\det {\begin{bmatrix}A_{x}&A_{y}&1\\B_{x}&B_{y}&1\\C_{x}&C_{y}&1\end{bmatrix}},\\[5pt] b&=\det {\begin{bmatrix}A_{x}&A_{y}&|\mathbf {A} |^{2}\\B_{x}&B_{y}&|\mathbf {B} |^{2}\\C_{x}&C_{y}&|\mathbf {C} |^{2}\end{bmatrix}} \end{aligned}}\]

Circumcenter: \[\frac{\mathbf{S}}{a}\]

Circumradius: \[\sqrt{\frac{b}{a} + \frac{|\mathbf{S}|^2}{a ^ 2}}\]

Erect the Fence II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public double[] outerTrees(int[][] trees) {
    return welzl(trees, new ArrayList<>(), 0);
}

// Welzl's algorithm
private double[] welzl(int[][] p, List<int[]> r, int offset) {
    if (offset == p.length || r.size() == 3) {
        return trivial(r);
    }

    double[] circle = welzl(p, r, offset + 1);

    if (isInside(circle, p[offset])) {
        return circle;
    }

    // backtrack
    r.add(p[offset]);
    circle = welzl(p, r, offset + 1);
    r.remove(r.size() - 1);
    return circle;
}

private double[] trivial(List<int[]> r) {
    if (r.isEmpty()) {
        return null;
    }

    if (r.size() == 1) {
        return new double[] {r.get(0)[0], r.get(0)[1], 0};
    }

    if (r.size() == 2) {
        return computeCircle2(r.get(0), r.get(1));
    }

    // if one angle is obtuse
    // - (r[0], r[1])
    // - (r[0], r[2])
    // - (r[1], r[2])
    for (int i = 0; i < 2; i++) {
        for (int j = i + 1; j < 3; j++) {
            double[] c = computeCircle2(r.get(i), r.get(j));
            if (isInside(c, r.get(3 - i - j))) {
                return c;
            }
        }
    }

    // circumscribed circle
    return computeCircumscribedCircle(r.get(0), r.get(1), r.get(2));
}

// Compute the circle whose diameter is [p1, p2]
private double[] computeCircle2(int[] p1, int[] p2) {
    double x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1];
    double r2 = squaredDistance(p1, p2);
    return new double[] {(x1 + x2) / 2, (y1 + y2) / 2, Math.sqrt(r2) / 2};
}

private double[] computeCircumscribedCircle(int[] p1, int[] p2, int[] p3) {
    int a2 = squaredDistance(p1), b2 = squaredDistance(p2), c2 = squaredDistance(p3);
    
    double sx = 0.5 * det(new double[][]{{a2, p1[1], 1}, {b2, p2[1], 1}, {c2, p3[1], 1}});
    double sy = 0.5 * det(new double[][]{{p1[0], a2, 1}, {p2[0], b2, 1}, {p3[0], c2, 1}});
    double a = det(new double[][]{{p1[0], p1[1], 1}, {p2[0], p2[1], 1}, {p3[0], p3[1], 1}});
    

    double[] center = new double[]{sx / a, sy / a};
    double r2 = squaredDistance(center, p1);
    return new double[] {center[0], center[1], Math.sqrt(r2)};
}

private boolean isInside(double[] circle, int[] point) {
    if (circle == null) {
        return false;
    }

    return squaredDistance(circle, point) <= circle[2] * circle[2];
}

// Squared Euclidean distance
private int squaredDistance(int[] p1, int[] p2) {
    return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
}

private int squaredDistance(int[] p) {
    return p[0] * p[0] + p[1] * p[1];
}

private double squaredDistance(double[] p1, int[] p2) {
    return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]);
}

// Determinant of 3 x 3 matrix
private double det(double[][] a) {
    double x = (a[1][1] * a[2][2]) - (a[2][1] * a[1][2]);
    double y = (a[1][0] * a[2][2]) - (a[2][0] * a[1][2]);
    double z = (a[1][0] * a[2][1]) - (a[2][0] * a[1][1]);

    return a[0][0] * x - a[0][1] * y + a[0][2] * z;
}

Rectangle

Strange Printer II

Find the indexes of four edges.

1
2
3
4
5
6
7
8
9
10
11
12
13
// {up, left, down, right}
Map<Integer, int[]> edges = new HashMap<>();

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        edges.putIfAbsent(targetGrid[i][j], new int[]{m, n, -1, -1});
        int[] p = edges.get(targetGrid[i][j]);
        p[0] = Math.min(p[0], i);
        p[1] = Math.min(p[1], j);
        p[2] = Math.max(p[2], i);
        p[3] = Math.max(p[3], j);
    }
}

Convex Hull

Monotone Chain: Andrew’s monotone chain convex hull algorithm constructs the convex hull of a set of 2-dimensional points in \(O(n\log n)\) time. It does so by first sorting the points lexicographically (first by x-coordinate, and in case of a tie, by y-coordinate), and then constructing upper and lower hulls of the points in \(O(n)\) time.

Orientation of a Simple Polygon

\[\mathbf {O} ={\begin{bmatrix}1&x_{A}&y_{A}\\1&x_{B}&y_{B}\\1&x_{C}&y_{C}\end{bmatrix}}\] \[\det(O)=(x_{B}-x_{A})(y_{C}-y_{A})-(x_{C}-x_{A})(y_{B}-y_{A})\]

Erect the Fence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Convex Hull
// Monotone Chain
public int[][] outerTrees(int[][] points) {
    // sort the point of P by x-coordinate
    // in case of a tie, by y-coordinate
    Arrays.sort(points, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);

    // holds the vertices of upper and lower hulls
    List<int[]> lower = new ArrayList<>(), upper = new ArrayList<>();

    // builds Lower layer of hulls
    for (int[] p : points) {
        // while the 3 points are clockwise turn
        while (lower.size() >= 2 &&
               clockwise(lower.get(lower.size() - 2), lower.get(lower.size() - 1), p)) {
            lower.remove(lower.size() - 1);             // remove q on (p,q,r)
        }
        lower.add(p);
    }

    // builds upper layer of hulls
    for (int i = points.length - 1; i >= 0; i--) {
        // while the 3 points are clockwise turn
        while (upper.size() >= 2 &&
               clockwise(upper.get(upper.size() - 2), upper.get(upper.size() - 1), points[i])) {
            upper.remove(upper.size() - 1);             // remove q on (p,q,r)
        }
        upper.add(points[i]);
    }

    // concatenates L and U to obtain the convex hull of P.
    // points in the result will be listed in counter-clockwise order.
    // removes duplicates.
    Set<int[]> set = Stream.concat(lower.stream(), upper.stream())
        .collect(Collectors.toSet());

    int[][] perimeter = new int[set.size()][2];
    int i = 0;
    for (int[] p : set) {
        perimeter[i++] = p;
    }
    return perimeter;
}

// orientation
private boolean clockwise(int[] a, int[] b, int[] c) {
    return (b[1] - a[1]) * (c[0] - b[0])  - (b[0] - a[0]) * (c[1] - b[1]) > 0;
}

3-D

Building Boxes

To build the extra boxes:

@SuperWhw:

Building Boxes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int minimumBoxes(int n) {
    // sum = 1 + (1 + 2) + (1 + 2 + 3) + ... + (1 + 2 + ... + j)
    int sum = 0, i = 0, j = 0;
    while (sum < n) {
        sum += i += ++j;
    }

    if (sum == n) {
        return i;
    }

    // build extra boxes
    sum -= i;
    i -= j;
    j = 0;

    while (sum < n) {
        sum += ++j;
    }

    return i + j;
}
This post is licensed under CC BY 4.0 by the author.