马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
这是我本日的算法学习纪录。
2187. 完成旅途的最少时间
标题形貌
思绪
二分查找
解题过程
为什么可以使用二分查找?
题目的关键在于探求一个最小的时间 t,使得在时间 t 内全部公交车完成的总旅途次数 sum 大于便是 totalTrips。
我们可以观察到时间的单调性:假如时间 t 内可以完成 totalTrips 次旅途,那么任何大于 t 的时间 t' 肯定也可以完成(乃至完成更多)。反之,假如时间 t 内无法完成 totalTrips 次旅途(即 sum < totalTrips),那么任何小于 t 的时间 t'' 也肯定无法完成。
这种单调性(或称为“二段性”)是使用二分查找的条件。我们可以在一个大概的时间范围内(比方从 1 到一个充足大的上限)举行二分查找。
查找目标是什么?
我们要找的是满意 sum >= totalTrips 的最小时间 t。
二分步调:
- 确定查找范围 [left, right]。left 可以是 1,right 可以是一个公道的上界,比方 min(time) * totalTrips(即假设只有最快的车在跑,完玉成部路程所需的时间)。
- 取中心时间 mid = left + (right - left) / 2。
- 盘算在 mid 时间内,全部公交车能完成的总旅途次数 sum。sum = Σ (mid / time) 对全部 i 求和。
- 比力 sum 和 totalTrips:
- 假如 sum < totalTrips,分析 mid 时间太短,无法完成任务。真正的最短时间肯定在 mid 右侧,以是更新 left = mid + 1。
- 假如 sum >= totalTrips,分析 mid 时间大概是答案,大概大概另有更短的时间也满意条件。我们须要实验更小的时间,以是更新 right = mid - 1。
- 循环直到 left > right。终极的 left 就是满意条件的最小时间。
复杂度
- 时间复杂度: O ( N log M ) O(N \log M) O(NlogM)
- 此中 N 是公交车的数目 (time.length)。
- M 是二分查找的时间范围的上界。在代码中,上界设置为 min(time) * totalTrips。每次二分查找须要 O ( N ) O(N) O(N) 的时间来盘算 sum 函数,二分查找本身须要 O ( log M ) O(\log M) O(logM) 次迭代。
- 空间复杂度: O ( 1 ) O(1) O(1)
Code
- class Solution {
- public long minimumTime(int[] time, int totalTrips) {
- long left = 1, right = Integer.MAX_VALUE;
- for (int x : time) {
- right = Math.min(right, x);
- }
- right *= totalTrips;
- while (left <= right) {
- long mid = left + (right - left) / 2;
- if (sum(time, mid) < totalTrips) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
- return left;
- }
- private long sum(int[] arr, long k) {
- long sum = 0;
- for (int x : arr) {
- sum += (k / x);
- }
- return sum;
- }
- }
复制代码 34. 在排序数组中查找元素的第一个和末了一个位置(复习)
标题形貌
本日是第二次写这道题,和前次相比已经明白了步调,可以完全办理题目了。
具体题解见我之前的博文:逐日算法-250405
Code
- class Solution {
- public int[] searchRange(int[] nums, int target) {
- int left = check(nums, target);
- if (left == nums.length || nums[left] != target) {
- return new int[] {-1, -1};
- }
- int right = check(nums, target + 1) - 1;
- return new int[] {left, right};
- }
- private int check(int[] arr, int k) {
- int left = 0, right = arr.length - 1;
- while (left <= right) {
- int mid = left + (right - left) / 2;
- if (arr[mid] < k) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
- return left;
- }
- }
复制代码 2529. 正整数和负整数的最大计数(复习)
标题形貌
本日是第二次写这道题,写的已经很顺手了,就不外多表明了。
具体题解见我之前的博文:逐日算法-250406
Code
- class Solution {
- public int maximumCount(int[] nums) {
- int neg = check(nums, 0);
- int pos = check(nums, 1);
- return Math.max(neg, (nums.length - pos));
- }
- private int check(int[] arr, int k) {
- int left = 0, right = arr.length - 1;
- while (left <= right) {
- int mid = left + (right - left) / 2;
- if (arr[mid] < k) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
- return left;
- }
- }
复制代码
|