欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-15 08:17:35
...

题目

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-student-that-will-replace-the-chalk

一个班级里有 n 个学生,编号为 0 到 n - 1 。每个学生会依次回答问题,编号为 0 的学生先回答,然后是编号为 1 的学生,以此类推,直到编号为 n - 1 的学生,然后老师会重复这个过程,重新从编号为 0 的学生开始回答问题。

给你一个长度为 n 且下标从 0 开始的整数数组 chalk 和一个整数 k 。一开始粉笔盒里总共有 k 支粉笔。当编号为 i 的学生回答问题时,他会消耗 chalk[i] 支粉笔。如果剩余粉笔数量 严格小于 chalk[i] ,那么学生 i 需要 补充 粉笔。

请你返回需要 补充 粉笔的学生 编号 。

  • 示例 1:

输入:chalk = [5,1,5], k = 22
输出:0
解释:学生消耗粉笔情况如下:

  • 编号为 0 的学生使用 5 支粉笔,然后 k = 17 。
  • 编号为 1 的学生使用 1 支粉笔,然后 k = 16 。
  • 编号为 2 的学生使用 5 支粉笔,然后 k = 11 。
  • 编号为 0 的学生使用 5 支粉笔,然后 k = 6 。
  • 编号为 1 的学生使用 1 支粉笔,然后 k = 5 。
  • 编号为 2 的学生使用 5 支粉笔,然后 k = 0 。
    编号为 0 的学生没有足够的粉笔,所以他需要补充粉笔。
  • 示例 2:

输入:chalk = [3,4,1,2], k = 25
输出:1
解释:学生消耗粉笔情况如下:

  • 编号为 0 的学生使用 3 支粉笔,然后 k = 22 。
  • 编号为 1 的学生使用 4 支粉笔,然后 k = 18 。
  • 编号为 2 的学生使用 1 支粉笔,然后 k = 17 。
  • 编号为 3 的学生使用 2 支粉笔,然后 k = 15 。
  • 编号为 0 的学生使用 3 支粉笔,然后 k = 12 。
  • 编号为 1 的学生使用 4 支粉笔,然后 k = 8 。
  • 编号为 2 的学生使用 1 支粉笔,然后 k = 7 。
  • 编号为 3 的学生使用 2 支粉笔,然后 k = 5 。
  • 编号为 0 的学生使用 3 支粉笔,然后 k = 2 。
    编号为 1 的学生没有足够的粉笔,所以他需要补充粉笔。
  • 提示:

chalk.length == n
1 <= n <= 105
1 <= chalk[i] <= 105
1 <= k <= 109

解法

贪心算法模拟或者前缀和+二分查找法

  • 贪心算法模拟这一个过程,发现chalk列表的和是多少,反复的在k范围内进行循环,直到k的值小于需求的时候返回下标
  • 通过前缀和,来变成一个升序序列,然后通过取余之后二分查找法,找到那个最新大于k的值的那个点
class Solution:
    def chalkReplacer(self, chalk: List[int], k: int) -> int:
        # 解法一
        n = len(chalk)
        """
        total_sum = sum(chalk)
        k = k % total_sum
        for i in range(n):
            curr_res = chalk[i]
            if chalk[i] <= k:
                k -= chalk[i]
            else:
                return i
        """
        
        # 解法二 前缀和+二分法
        if chalk[0] > k:
            return 0
        for i in range(1, n):
            chalk[i] = chalk[i] + chalk[i-1]
            if chalk[i] > k:
                return i
        
        k %= chalk[-1]
        return bisect_right(chalk, k)
    
    def bisect_right(self, chalk: List[int], k: int) -> int:
        left = 0
        right = len(chalk)
        mid = left + (right-left) // 2
        while left <= right:
            if chalk[mid] > k:
                right = mid
            else:
                left = mid + 1
        return right
       
  • c++
class Solution {
public:
    int chalkReplacer(vector<int>& chalk, int k) {
        int n = chalk.size();
        /*
        long long total = accumulate(chalk.begin(), chalk.end(), 0LL);
        k %= total;
        int res = -1;
        for(int i=0; i< n; i++)
        {
            if(chalk[i] <= k)
            {
                k -= chalk[i];
            }
            else
            {
                res = i;
                break;
            }
        }
        return res;
        */

        // 前缀和
        if(chalk[0] > k)
        {
            return 0;
        }
        for(int i=1; i< n; i++)
        {
            chalk[i] = chalk[i] + chalk[i-1];
            if (chalk[i] > k)
            {
                return i;
            }
        }

        // k %= chalk.back();
        k %= chalk[n-1];
        //return upper_bound(chalk.begin(), chalk.end(), k) - chalk.begin();
        int left = 0;
        int right = n;
        while(left < right)
        {
            int mid = left + (right-left) /2;
            if(chalk[mid] > k)
            {
                right = mid;
            }
            else
            {
                left = mid + 1;
            }
        }
        return right;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组chalk中所有的长度
  • 空间复杂度:O(1)