Welcome to Subscribe On Youtube

3102. Minimize Manhattan Distances

Description

You are given a array points representing integer coordinates of some points on a 2D plane, where points[i] = [xi, yi].

The distance between two points is defined as their Manhattan distance.

Return the minimum possible value for maximum distance between any two points by removing exactly one point.

 

Example 1:

Input: points = [[3,10],[5,15],[10,2],[4,4]]

Output: 12

Explanation:

The maximum distance after removing each point is the following:

  • After removing the 0th point the maximum distance is between points (5, 15) and (10, 2), which is \|5 - 10\| + \|15 - 2\| = 18.
  • After removing the 1st point the maximum distance is between points (3, 10) and (10, 2), which is \|3 - 10\| + \|10 - 2\| = 15.
  • After removing the 2nd point the maximum distance is between points (5, 15) and (4, 4), which is \|5 - 4\| + \|15 - 4\| = 12.
  • After removing the 3rd point the maximum distance is between points (5, 15) and (10, 2), which is \|5 - 10\| + \|15 - 2\| = 18.

12 is the minimum possible maximum distance between any two points after removing exactly one point.

Example 2:

Input: points = [[1,1],[1,1],[1,1]]

Output: 0

Explanation:

Removing any of the points results in the maximum distance between any two points of 0.

 

Constraints:

  • 3 <= points.length <= 105
  • points[i].length == 2
  • 1 <= points[i][0], points[i][1] <= 108

Solutions

Solution 1

  • class Solution {
        public int minimumDistance(int[][] points) {
            TreeMap<Integer, Integer> tm1 = new TreeMap<>();
            TreeMap<Integer, Integer> tm2 = new TreeMap<>();
            for (int[] p : points) {
                int x = p[0], y = p[1];
                tm1.merge(x + y, 1, Integer::sum);
                tm2.merge(x - y, 1, Integer::sum);
            }
            int ans = Integer.MAX_VALUE;
            for (int[] p : points) {
                int x = p[0], y = p[1];
                if (tm1.merge(x + y, -1, Integer::sum) == 0) {
                    tm1.remove(x + y);
                }
                if (tm2.merge(x - y, -1, Integer::sum) == 0) {
                    tm2.remove(x - y);
                }
                ans = Math.min(
                    ans, Math.max(tm1.lastKey() - tm1.firstKey(), tm2.lastKey() - tm2.firstKey()));
                tm1.merge(x + y, 1, Integer::sum);
                tm2.merge(x - y, 1, Integer::sum);
            }
            return ans;
        }
    }
    
  • class Solution {
    public:
        int minimumDistance(vector<vector<int>>& points) {
            multiset<int> st1;
            multiset<int> st2;
            for (auto& p : points) {
                int x = p[0], y = p[1];
                st1.insert(x + y);
                st2.insert(x - y);
            }
            int ans = INT_MAX;
            for (auto& p : points) {
                int x = p[0], y = p[1];
                st1.erase(st1.find(x + y));
                st2.erase(st2.find(x - y));
                ans = min(ans, max(*st1.rbegin() - *st1.begin(), *st2.rbegin() - *st2.begin()));
                st1.insert(x + y);
                st2.insert(x - y);
            }
            return ans;
        }
    };
    
  • from sortedcontainers import SortedList
    
    
    class Solution:
        def minimumDistance(self, points: List[List[int]]) -> int:
            sl1 = SortedList()
            sl2 = SortedList()
            for x, y in points:
                sl1.add(x + y)
                sl2.add(x - y)
            ans = inf
            for x, y in points:
                sl1.remove(x + y)
                sl2.remove(x - y)
                ans = min(ans, max(sl1[-1] - sl1[0], sl2[-1] - sl2[0]))
                sl1.add(x + y)
                sl2.add(x - y)
            return ans
    
    
  • func minimumDistance(points [][]int) int {
    	st1 := redblacktree.New[int, int]()
    	st2 := redblacktree.New[int, int]()
    	merge := func(st *redblacktree.Tree[int, int], x, v int) {
    		c, _ := st.Get(x)
    		if c+v == 0 {
    			st.Remove(x)
    		} else {
    			st.Put(x, c+v)
    		}
    	}
    	for _, p := range points {
    		x, y := p[0], p[1]
    		merge(st1, x+y, 1)
    		merge(st2, x-y, 1)
    	}
    	ans := math.MaxInt
    	for _, p := range points {
    		x, y := p[0], p[1]
    		merge(st1, x+y, -1)
    		merge(st2, x-y, -1)
    		ans = min(ans, max(st1.Right().Key-st1.Left().Key, st2.Right().Key-st2.Left().Key))
    		merge(st1, x+y, 1)
    		merge(st2, x-y, 1)
    	}
    	return ans
    }
    
  • function minimumDistance(points: number[][]): number {
        const st1 = new TreapMultiSet<number>();
        const st2 = new TreapMultiSet<number>();
        for (const [x, y] of points) {
            st1.add(x + y);
            st2.add(x - y);
        }
        let ans = Infinity;
        for (const [x, y] of points) {
            st1.delete(x + y);
            st2.delete(x - y);
            ans = Math.min(ans, Math.max(st1.last() - st1.first(), st2.last() - st2.first()));
            st1.add(x + y);
            st2.add(x - y);
        }
        return ans;
    }
    
    type CompareFunction<T, R extends 'number' | 'boolean'> = (
        a: T,
        b: T,
    ) => R extends 'number' ? number : boolean;
    
    interface ITreapMultiSet<T> extends Iterable<T> {
        add: (...value: T[]) => this;
        has: (value: T) => boolean;
        delete: (value: T) => void;
    
        bisectLeft: (value: T) => number;
        bisectRight: (value: T) => number;
    
        indexOf: (value: T) => number;
        lastIndexOf: (value: T) => number;
    
        at: (index: number) => T | undefined;
        first: () => T | undefined;
        last: () => T | undefined;
    
        lower: (value: T) => T | undefined;
        higher: (value: T) => T | undefined;
        floor: (value: T) => T | undefined;
        ceil: (value: T) => T | undefined;
    
        shift: () => T | undefined;
        pop: (index?: number) => T | undefined;
    
        count: (value: T) => number;
    
        keys: () => IterableIterator<T>;
        values: () => IterableIterator<T>;
        rvalues: () => IterableIterator<T>;
        entries: () => IterableIterator<[number, T]>;
    
        readonly size: number;
    }
    
    class TreapNode<T = number> {
        value: T;
        count: number;
        size: number;
        priority: number;
        left: TreapNode<T> | null;
        right: TreapNode<T> | null;
    
        constructor(value: T) {
            this.value = value;
            this.count = 1;
            this.size = 1;
            this.priority = Math.random();
            this.left = null;
            this.right = null;
        }
    
        static getSize(node: TreapNode<any> | null): number {
            return node?.size ?? 0;
        }
    
        static getFac(node: TreapNode<any> | null): number {
            return node?.priority ?? 0;
        }
    
        pushUp(): void {
            let tmp = this.count;
            tmp += TreapNode.getSize(this.left);
            tmp += TreapNode.getSize(this.right);
            this.size = tmp;
        }
    
        rotateRight(): TreapNode<T> {
            // eslint-disable-next-line @typescript-eslint/no-this-alias
            let node: TreapNode<T> = this;
            const left = node.left;
            node.left = left?.right ?? null;
            left && (left.right = node);
            left && (node = left);
            node.right?.pushUp();
            node.pushUp();
            return node;
        }
    
        rotateLeft(): TreapNode<T> {
            // eslint-disable-next-line @typescript-eslint/no-this-alias
            let node: TreapNode<T> = this;
            const right = node.right;
            node.right = right?.left ?? null;
            right && (right.left = node);
            right && (node = right);
            node.left?.pushUp();
            node.pushUp();
            return node;
        }
    }
    
    class TreapMultiSet<T = number> implements ITreapMultiSet<T> {
        private readonly root: TreapNode<T>;
        private readonly compareFn: CompareFunction<T, 'number'>;
        private readonly leftBound: T;
        private readonly rightBound: T;
    
        constructor(compareFn?: CompareFunction<T, 'number'>);
        constructor(compareFn: CompareFunction<T, 'number'>, leftBound: T, rightBound: T);
        constructor(
            compareFn: CompareFunction<T, any> = (a: any, b: any) => a - b,
            leftBound: any = -Infinity,
            rightBound: any = Infinity,
        ) {
            this.root = new TreapNode<T>(rightBound);
            this.root.priority = Infinity;
            this.root.left = new TreapNode<T>(leftBound);
            this.root.left.priority = -Infinity;
            this.root.pushUp();
    
            this.leftBound = leftBound;
            this.rightBound = rightBound;
            this.compareFn = compareFn;
        }
    
        get size(): number {
            return this.root.size - 2;
        }
    
        get height(): number {
            const getHeight = (node: TreapNode<T> | null): number => {
                if (node == null) return 0;
                return 1 + Math.max(getHeight(node.left), getHeight(node.right));
            };
    
            return getHeight(this.root);
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns true if value is a member.
         */
        has(value: T): boolean {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): boolean => {
                if (node == null) return false;
                if (compare(node.value, value) === 0) return true;
                if (compare(node.value, value) < 0) return dfs(node.right, value);
                return dfs(node.left, value);
            };
    
            return dfs(this.root, value);
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Add value to sorted set.
         */
        add(...values: T[]): this {
            const compare = this.compareFn;
            const dfs = (
                node: TreapNode<T> | null,
                value: T,
                parent: TreapNode<T>,
                direction: 'left' | 'right',
            ): void => {
                if (node == null) return;
                if (compare(node.value, value) === 0) {
                    node.count++;
                    node.pushUp();
                } else if (compare(node.value, value) > 0) {
                    if (node.left) {
                        dfs(node.left, value, node, 'left');
                    } else {
                        node.left = new TreapNode(value);
                        node.pushUp();
                    }
    
                    if (TreapNode.getFac(node.left) > node.priority) {
                        parent[direction] = node.rotateRight();
                    }
                } else if (compare(node.value, value) < 0) {
                    if (node.right) {
                        dfs(node.right, value, node, 'right');
                    } else {
                        node.right = new TreapNode(value);
                        node.pushUp();
                    }
    
                    if (TreapNode.getFac(node.right) > node.priority) {
                        parent[direction] = node.rotateLeft();
                    }
                }
                parent.pushUp();
            };
    
            values.forEach(value => dfs(this.root.left, value, this.root, 'left'));
            return this;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Remove value from sorted set if it is a member.
         * If value is not a member, do nothing.
         */
        delete(value: T): void {
            const compare = this.compareFn;
            const dfs = (
                node: TreapNode<T> | null,
                value: T,
                parent: TreapNode<T>,
                direction: 'left' | 'right',
            ): void => {
                if (node == null) return;
    
                if (compare(node.value, value) === 0) {
                    if (node.count > 1) {
                        node.count--;
                        node?.pushUp();
                    } else if (node.left == null && node.right == null) {
                        parent[direction] = null;
                    } else {
                        // 旋到根节点
                        if (
                            node.right == null ||
                            TreapNode.getFac(node.left) > TreapNode.getFac(node.right)
                        ) {
                            parent[direction] = node.rotateRight();
                            dfs(parent[direction]?.right ?? null, value, parent[direction]!, 'right');
                        } else {
                            parent[direction] = node.rotateLeft();
                            dfs(parent[direction]?.left ?? null, value, parent[direction]!, 'left');
                        }
                    }
                } else if (compare(node.value, value) > 0) {
                    dfs(node.left, value, node, 'left');
                } else if (compare(node.value, value) < 0) {
                    dfs(node.right, value, node, 'right');
                }
    
                parent?.pushUp();
            };
    
            dfs(this.root.left, value, this.root, 'left');
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns an index to insert value in the sorted set.
         * If the value is already present, the insertion point will be before (to the left of) any existing values.
         */
        bisectLeft(value: T): number {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): number => {
                if (node == null) return 0;
    
                if (compare(node.value, value) === 0) {
                    return TreapNode.getSize(node.left);
                } else if (compare(node.value, value) > 0) {
                    return dfs(node.left, value);
                } else if (compare(node.value, value) < 0) {
                    return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count;
                }
    
                return 0;
            };
    
            return dfs(this.root, value) - 1;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns an index to insert value in the sorted set.
         * If the value is already present, the insertion point will be before (to the right of) any existing values.
         */
        bisectRight(value: T): number {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): number => {
                if (node == null) return 0;
    
                if (compare(node.value, value) === 0) {
                    return TreapNode.getSize(node.left) + node.count;
                } else if (compare(node.value, value) > 0) {
                    return dfs(node.left, value);
                } else if (compare(node.value, value) < 0) {
                    return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count;
                }
    
                return 0;
            };
            return dfs(this.root, value) - 1;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns the index of the first occurrence of a value in the set, or -1 if it is not present.
         */
        indexOf(value: T): number {
            const compare = this.compareFn;
            let isExist = false;
    
            const dfs = (node: TreapNode<T> | null, value: T): number => {
                if (node == null) return 0;
    
                if (compare(node.value, value) === 0) {
                    isExist = true;
                    return TreapNode.getSize(node.left);
                } else if (compare(node.value, value) > 0) {
                    return dfs(node.left, value);
                } else if (compare(node.value, value) < 0) {
                    return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count;
                }
    
                return 0;
            };
            const res = dfs(this.root, value) - 1;
            return isExist ? res : -1;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns the index of the last occurrence of a value in the set, or -1 if it is not present.
         */
        lastIndexOf(value: T): number {
            const compare = this.compareFn;
            let isExist = false;
    
            const dfs = (node: TreapNode<T> | null, value: T): number => {
                if (node == null) return 0;
    
                if (compare(node.value, value) === 0) {
                    isExist = true;
                    return TreapNode.getSize(node.left) + node.count - 1;
                } else if (compare(node.value, value) > 0) {
                    return dfs(node.left, value);
                } else if (compare(node.value, value) < 0) {
                    return dfs(node.right, value) + TreapNode.getSize(node.left) + node.count;
                }
    
                return 0;
            };
    
            const res = dfs(this.root, value) - 1;
            return isExist ? res : -1;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Returns the item located at the specified index.
         * @param index The zero-based index of the desired code unit. A negative index will count back from the last item.
         */
        at(index: number): T | undefined {
            if (index < 0) index += this.size;
            if (index < 0 || index >= this.size) return undefined;
    
            const dfs = (node: TreapNode<T> | null, rank: number): T | undefined => {
                if (node == null) return undefined;
    
                if (TreapNode.getSize(node.left) >= rank) {
                    return dfs(node.left, rank);
                } else if (TreapNode.getSize(node.left) + node.count >= rank) {
                    return node.value;
                } else {
                    return dfs(node.right, rank - TreapNode.getSize(node.left) - node.count);
                }
            };
    
            const res = dfs(this.root, index + 2);
            return ([this.leftBound, this.rightBound] as any[]).includes(res) ? undefined : res;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Find and return the element less than `val`, return `undefined` if no such element found.
         */
        lower(value: T): T | undefined {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): T | undefined => {
                if (node == null) return undefined;
                if (compare(node.value, value) >= 0) return dfs(node.left, value);
    
                const tmp = dfs(node.right, value);
                if (tmp == null || compare(node.value, tmp) > 0) {
                    return node.value;
                } else {
                    return tmp;
                }
            };
    
            const res = dfs(this.root, value) as any;
            return res === this.leftBound ? undefined : res;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Find and return the element greater than `val`, return `undefined` if no such element found.
         */
        higher(value: T): T | undefined {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): T | undefined => {
                if (node == null) return undefined;
                if (compare(node.value, value) <= 0) return dfs(node.right, value);
    
                const tmp = dfs(node.left, value);
    
                if (tmp == null || compare(node.value, tmp) < 0) {
                    return node.value;
                } else {
                    return tmp;
                }
            };
    
            const res = dfs(this.root, value) as any;
            return res === this.rightBound ? undefined : res;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Find and return the element less than or equal to `val`, return `undefined` if no such element found.
         */
        floor(value: T): T | undefined {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): T | undefined => {
                if (node == null) return undefined;
                if (compare(node.value, value) === 0) return node.value;
                if (compare(node.value, value) >= 0) return dfs(node.left, value);
    
                const tmp = dfs(node.right, value);
                if (tmp == null || compare(node.value, tmp) > 0) {
                    return node.value;
                } else {
                    return tmp;
                }
            };
    
            const res = dfs(this.root, value) as any;
            return res === this.leftBound ? undefined : res;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description Find and return the element greater than or equal to `val`, return `undefined` if no such element found.
         */
        ceil(value: T): T | undefined {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): T | undefined => {
                if (node == null) return undefined;
                if (compare(node.value, value) === 0) return node.value;
                if (compare(node.value, value) <= 0) return dfs(node.right, value);
    
                const tmp = dfs(node.left, value);
    
                if (tmp == null || compare(node.value, tmp) < 0) {
                    return node.value;
                } else {
                    return tmp;
                }
            };
    
            const res = dfs(this.root, value) as any;
            return res === this.rightBound ? undefined : res;
        }
    
        /**
         * @complexity `O(logn)`
         * @description
         * Returns the last element from set.
         * If the set is empty, undefined is returned.
         */
        first(): T | undefined {
            const iter = this.inOrder();
            iter.next();
            const res = iter.next().value;
            return res === this.rightBound ? undefined : res;
        }
    
        /**
         * @complexity `O(logn)`
         * @description
         * Returns the last element from set.
         * If the set is empty, undefined is returned .
         */
        last(): T | undefined {
            const iter = this.reverseInOrder();
            iter.next();
            const res = iter.next().value;
            return res === this.leftBound ? undefined : res;
        }
    
        /**
         * @complexity `O(logn)`
         * @description
         * Removes the first element from an set and returns it.
         * If the set is empty, undefined is returned and the set is not modified.
         */
        shift(): T | undefined {
            const first = this.first();
            if (first === undefined) return undefined;
            this.delete(first);
            return first;
        }
    
        /**
         * @complexity `O(logn)`
         * @description
         * Removes the last element from an set and returns it.
         * If the set is empty, undefined is returned and the set is not modified.
         */
        pop(index?: number): T | undefined {
            if (index == null) {
                const last = this.last();
                if (last === undefined) return undefined;
                this.delete(last);
                return last;
            }
    
            const toDelete = this.at(index);
            if (toDelete == null) return;
            this.delete(toDelete);
            return toDelete;
        }
    
        /**
         *
         * @complexity `O(logn)`
         * @description
         * Returns number of occurrences of value in the sorted set.
         */
        count(value: T): number {
            const compare = this.compareFn;
            const dfs = (node: TreapNode<T> | null, value: T): number => {
                if (node == null) return 0;
                if (compare(node.value, value) === 0) return node.count;
                if (compare(node.value, value) < 0) return dfs(node.right, value);
                return dfs(node.left, value);
            };
    
            return dfs(this.root, value);
        }
    
        *[Symbol.iterator](): Generator<T, any, any> {
            yield* this.values();
        }
    
        /**
         * @description
         * Returns an iterable of keys in the set.
         */
        *keys(): Generator<T, any, any> {
            yield* this.values();
        }
    
        /**
         * @description
         * Returns an iterable of values in the set.
         */
        *values(): Generator<T, any, any> {
            const iter = this.inOrder();
            iter.next();
            const steps = this.size;
            for (let _ = 0; _ < steps; _++) {
                yield iter.next().value;
            }
        }
    
        /**
         * @description
         * Returns a generator for reversed order traversing the set.
         */
        *rvalues(): Generator<T, any, any> {
            const iter = this.reverseInOrder();
            iter.next();
            const steps = this.size;
            for (let _ = 0; _ < steps; _++) {
                yield iter.next().value;
            }
        }
    
        /**
         * @description
         * Returns an iterable of key, value pairs for every entry in the set.
         */
        *entries(): IterableIterator<[number, T]> {
            const iter = this.inOrder();
            iter.next();
            const steps = this.size;
            for (let i = 0; i < steps; i++) {
                yield [i, iter.next().value];
            }
        }
    
        private *inOrder(root: TreapNode<T> | null = this.root): Generator<T, any, any> {
            if (root == null) return;
            yield* this.inOrder(root.left);
            const count = root.count;
            for (let _ = 0; _ < count; _++) {
                yield root.value;
            }
            yield* this.inOrder(root.right);
        }
    
        private *reverseInOrder(root: TreapNode<T> | null = this.root): Generator<T, any, any> {
            if (root == null) return;
            yield* this.reverseInOrder(root.right);
            const count = root.count;
            for (let _ = 0; _ < count; _++) {
                yield root.value;
            }
            yield* this.reverseInOrder(root.left);
        }
    }
    
    

All Problems

All Solutions