[M前缀和] lc1894. 找到需要补充粉笔的学生编号(二分+模拟+坑点)

博客探讨了一个编程问题,涉及数组处理和二分查找。题目要求根据学生使用粉笔的情况找到需要补充粉笔的学生编号。文章指出在处理过程中需要注意数据边界和取模运算的影响,提出使用二分查找或直接遍历的方法来解决。优化后的解决方案具有线性时间和常数空间复杂度。
摘要由CSDN通过智能技术生成

1. 题目来源

链接:1894. 找到需要补充粉笔的学生编号

2. 题目解析

有个坑点,有点恶心。首先被数据坑一把,需要开 LL,然后被边界坑一把…

先求前缀和,然后 ka[n-1] 取模,然后二分出小于等于 k 的最大值即可。注意,然后就被坑了。 因为小于等于 k 意味着当前同学可以用完粉笔,下一个同学不能用完粉笔,然后就需要返回 l+1然而在 k 在对 a[n-1] 取模的时候,以及初始情况都可能导致 k<a[0],此时当然应该返回 a[0],然而直接返回 a[l+1] 等价于返回 a[1] 肯定是错误的。

所以,二分完之后,a[l] 并不一定是小于等于 k 的,也就是 l+1 这个人并不一定是最终答案,l 也可能是答案。


当然,得到总和,取模之后完全不必要二分。直接遍历一遍,到哪个人粉笔不够了,当然就要输出那个人的编号了。这样就不需要额外开空间了。


  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
public:
    int chalkReplacer(vector<int>& chalk, int k) {
        using LL = long long;
        int n = chalk.size();
        vector<LL> a; 
        for (auto e : chalk) a.push_back(e);
        for (int i = 1; i < n; i ++ ) a[i] += a[i - 1];
        k %= a[n - 1];
        int l = 0, r = n - 1;
        while (l < r) {                         // 二分小于等于 k 的最大的一个位置
            int mid = l + r + 1 >> 1;
            if (a[mid] > k) r = mid - 1;
            else l = mid;
        }

        // 如果小于等于 k,那么是下一个同学铅笔不够,即返回l+1,否则就是本同学铅笔不够
        // 值得注意的是,二分停下来的位置按理说一定是 a[l]<=k 的
        // 下面这个三目运算符怎么会取到 a[l]>k 的情况呢?
        // 实际上因为有 k%=a[n - 1]这个操作,可能会导致 a[0]>k,导致需要返回 0 下标,
        // 所有的 a[mid]>k,导致右边界一直缩小到 l,此时 l=r=0
        // 所以唯一的情况就是当第一个 a[0]>k 时,二分才会停在 0 的位置,返回l=r=0即可,
        // 其它情况都是 a[l]<=k,需要返回 l+1 或者 r+1
        // if (a[0] > k) return 0;
        // return a[l] <= k ? l + 1 : l - 1000; 后面的不会被执行到
        return a[l] <= k ? l + 1 : l;
    }
};

go 代码

func chalkReplacer(chalk []int, k int) int {
    n := len(chalk)
    sum := 0
    for i := 0; i < n; i ++ {
        sum += chalk[i]
    }

    k %= sum
    for i := 0; i < n; i ++ {
        if chalk[i] > k {
            return i
        }
        k -= chalk[i]
    }

    return -1
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值