[Java/Python 3] Binary Search.
Q & A:\n\nQ1: What is the logic behind setting higher bound for binary search as hi = 1L * maxRank * cars * cars?\n \n A1: The one with highest rank repairing a
**Q & A:**\n\n*Q1:* What is the logic behind setting higher bound for binary search as `hi = 1L * maxRank * cars * cars`?\n \n *A1:* The one with highest rank repairing all cars will cost longest time, and there is no way that we could spend more time to finish all jobs. Therefore, we set the worst case of `L * maxRank * cars * cars` as the higher bound of our search space.\n\n**Q & A:**\n\n----\n\n1. The worst case is that the max rank repairs all cars, and the corresponding time cost is the higher bound of our search space;\n2. Set the lower bound as `0`;\n3. Binary search the minimum time need to repair all cars.\n\n```java\n    public long repairCars(int[] ranks, int cars) {\n        int maxRank = IntStream.of(ranks).max().getAsInt();\n        long lo = 0, hi = 1L * maxRank * cars * cars;\n        while (lo < hi) {\n            long time = lo + (hi - lo) / 2;\n            if (canFinish(ranks, cars, time)) {\n                hi = time;\n            }else {\n                lo = time + 1;\n            }\n        }\n        return lo;\n    }\n    private boolean canFinish(int[] ranks, int cars, long time) {\n        long finish = 0;\n        for (int r : ranks) {\n            finish += (int)Math.floor(Math.sqrt(time / r));\n            if (finish >= cars) {\n                return true;\n            }\n        }\n        return false;\n    }\n```\n\n```python\n    def repairCars(self, ranks: List[int], cars: int) -> int:\n        \n        def canFinish(time: int) -> bool:\n            finish = 0\n            for r in ranks:\n                finish += floor(math.sqrt(time / r))\n                if finish >= cars:\n                    return True\n            return False\n\n        lo, hi = 0, max(ranks) * cars * cars\n        while lo < hi:\n            time = lo + (hi - lo) // 2\n            if canFinish(time):\n                hi = time\n            else:\n                lo = time + 1\n        return lo\n```\nSince Python 3.10 we can simplify the above code as follows:\n```python\n    def repairCars(self, ranks: List[int], cars: int) -> int:\n        return bisect_left(range(max(ranks) * cars * cars), cars, key=lambda x: sum(floor(math.sqrt(x // r)) for r in ranks))\n```\n\n**Analysis:**\n\nTime: `O(nlog(max(ranks) * m * m))`, space: `O(1)`, where `n = ranks.length, m = cars`.
['Java', 'Python3']