每日算法-250409

这是我今天的算法学习记录。


2187. 完成旅途的最少时间

题目描述

LeetCode 2187 题目截图

思路

二分查找

解题过程

为什么可以使用二分查找?

问题的关键在于寻找一个最小 的时间 t,使得在时间 t 内所有公交车完成的总旅途次数 sum 大于等于 totalTrips

我们可以观察到时间的单调性:如果时间 t 内可以完成 totalTrips 次旅途,那么任何大于 t 的时间 t' 肯定也可以完成(甚至完成更多)。反之,如果时间 t 内无法完成 totalTrips 次旅途(即 sum < totalTrips),那么任何小于 t 的时间 t'' 也肯定无法完成。

这种单调性(或称为"二段性")是使用二分查找的前提。我们可以在一个可能的时间范围内(例如从 1 到一个足够大的上限)进行二分查找。

查找目标是什么?

我们要找的是满足 sum >= totalTrips最小 时间 t

二分步骤:

  1. 确定查找范围 [left, right]left 可以是 1,right 可以是一个合理的上界,例如 min(time) * totalTrips(即假设只有最快的车在跑,完成所有旅程所需的时间)。
  2. 取中间时间 mid = left + (right - left) / 2
  3. 计算在 mid 时间内,所有公交车能完成的总旅途次数 sumsum = Σ (mid / time[i]) 对所有 i 求和。
  4. 比较 sumtotalTrips
    • 如果 sum < totalTrips,说明 mid 时间太短,无法完成任务。真正的最短时间一定在 mid 右侧,所以更新 left = mid + 1
    • 如果 sum >= totalTrips,说明 mid 时间可能 是答案,或者可能还有更短的时间也满足条件。我们需要尝试更小的时间,所以更新 right = mid - 1
  5. 循环直到 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

java 复制代码
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. 在排序数组中查找元素的第一个和最后一个位置(复习)

题目描述

LeetCode 34 题目截图

今天是第二次写这道题,和上次相比已经理解了步骤,可以完全解决问题了。

详细题解见我之前的博文:每日算法-250405

Code

java 复制代码
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. 正整数和负整数的最大计数(复习)

题目描述

LeetCode 2529 题目截图

今天是第二次写这道题,写的已经很顺手了,就不过多解释了。

详细题解见我之前的博文:每日算法-250406

Code

java 复制代码
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;
    }
}

相关推荐
BothSavage6 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn6 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽8 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰1 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术1 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六1 天前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术1 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize1 天前
初识DFS 与 BFS:递归、队列与图遍历
算法