77.优质章节的连续选择|Marscode AI刷题

1.题目

问题描述

在番茄小说的书籍中,编辑小S正在寻找精彩的连续章节以进行特色展示。每个章节都有各自的文字数量,编辑希望选出的连续章节总字数不超过 k。在这些连续章节中,除了第一章和最后一章,任何字数多于前后章节的章节都被视为优质章节。编辑的目标是挑选出尽可能多的优质章节,同时满足总字数限制。如果有多个答案优质章节数相同,请输出总字数最少的答案。优质章节数和总字数均相同,则输出区间下标最小的答案。

例如,假设章节字数为 [1000, 3000, 2000, 4000, 3000, 2000, 4000, 2000],给定的字数上限 k 为 15000。一种优选方案是选择从第1章到第5章,其中第2章和第4章是优质章节。

输入:

  • n:章节数目
  • k:总字数上限
  • array_a:各个章节的字数

返回规则如下:

  • 返回一个字符串,格式为"优质章节数,优质章节数最多的区间左下标,优质章节数最多的区间右下标"

测试样例

样例1:

输入:n = 8,k = 15000,array_a = [1000, 3000, 2000, 4000, 3000, 2000, 4000, 2000]

输出:'2,1,5'

样例2:

输入:n = 8,k = 15000,array_a = [2000, 5000, 2000, 1000, 4000, 2000, 4000, 3000]

输出:'2,4,8'

样例3:

输入:n = 5,k = 10000,array_a = [3000, 4000, 1000, 5000, 2000]

输出:'1,1,3'

样例4:

输入:n = 6,k = 8000,array_a = [1000, 2000, 3000, 4000, 500, 2500]

输出:'1,3,5'

样例5:

输入:n = 10,k = 5000,array_a = [500, 1000, 1500, 500, 500, 1000, 1500, 500, 500, 1000]

输出:'1,2,4'

2.思路

  • 计算前缀和(sum_array
    • 由于我们需要计算某一连续区间内的字数总和,所以我们可以用前缀和数组 sum_array 来快速计算任意区间的字数总和。
    • sum_array[i] 表示从第1章到第i章的字数累计和。这样,区间 array_a[left]array_a[right] 的总字数可以通过 sum_array[right] - sum_array[left - 1] 来快速得到。
  • 遍历章节
    • 从第二章到倒数第二章(因为第一章和最后一章无法成为优质章节,缺少前后章节的比较)进行遍历。
    • 对于每一章,判断它是否是一个局部最大值,即它的字数是否大于前一章和后一章。如果是局部最大值,说明这章是一个优质章节。
  • 队列的使用
    • 使用 deque(双端队列)来存储当前可能的优质章节区间索引。
    • 为了确保区间总字数不超过上限 k,当队列中的章节字数和超过 k 时,我们会从队列的头部移除一些章节,直到总字数满足要求。
  • 更新最优解
    • 每次更新队列时,检查当前区间的优质章节数量和总字数:
      • 如果当前区间的优质章节数比之前的区间多,则更新最优解。
      • 如果优质章节数相同,则比较总字数,选取字数最少的区间。
      • 如果优质章节数和总字数都相同,则选择左端下标最小的区间。
  • 最终返回结果
    • 遍历完所有章节后,返回优质章节数、区间的左端下标和右端下标。

3.代码

#include <iostream>
#include <vector>
#include <string>
#include <deque>
#include <cassert>
using namespace std;

std::string solution(int n, int k, std::vector<int> array_a) {
    // Please write your code here
    // 校验输入的合法性
    assert(n == array_a.size());
    assert(3 <= n && n <= 100000);
    assert(0 <= k && k <= 1000000000);

    // 初始化一个数组sum_array,用于存储从第1章到第i章的字数累计和
    vector<int> sum_array(n, 0);
    sum_array[0] = array_a[0];
    for (int i = 1; i < n; i++) {
        sum_array[i] = sum_array[i - 1] + array_a[i];
        // 校验每章的字数是否合法
        assert(1 <= array_a[i] && array_a[i] <= 10000000);
    }
    // 定义一个lambda表达式,用于获取从第left章到第right章的字数之和
    auto get_sum_from_a_to_b = [&](int left, int right) {
        return(sum_array[right] - (left > 0 ? sum_array[left - 1] : 0));
    };
    // 使用队列deque来存储可能的优质章节索引
    deque<int> q;
    int ans = 0, start = -1, end = -1, total_size = -1; // 初始化答案变量
    // 遍历每章,寻找优质章节
    for (int i = 1; i < n - 1; ++i) {
        // 判断当前章节是否是局部最大值(优质章节的定义)
        if (array_a[i] > array_a[i - 1] && array_a[i] > array_a[i + 1]) {
            q.push_back(i);

            // 如果队列中的章节总字数超过k,则从队列头部移除章节,直到满足字数限制
            while (!q.empty() && get_sum_from_a_to_b(q.front() - 1, q.back() + 1) > k) {
                q.pop_front(); 
            }
            // 如果队列非空,则检查当前的区间并更新答案
            if (!q.empty()) {
                int current_size = get_sum_from_a_to_b(q.front() - 1, q.back() + 1);
                // 如果当前区间优质章节数更多,或优质章节数相同但字数更少,更新答案
                if (q.size() > ans || (q.size() == ans && total_size > current_size)) {
                    ans = q.size();
                    start = q.front() - 1;
                    end = q.back() + 1;
                    total_size = current_size;
                }
            }
        }
    }
    // 确保有有效的答案
    assert (ans != 0);
    // 返回符合要求的字符串,格式为 "优质章节数,区间左端下标,区间右端下标"
    return to_string(ans) + "," + to_string(start + 1) + "," + to_string(end + 1);
}

int main() {
    //  You can add more test cases here
    std::vector<int> array_a1 = {1000, 3000, 2000, 4000, 3000, 2000, 4000, 2000};
    std::vector<int> array_a2 = {2000, 5000, 2000, 1000, 4000, 2000, 4000, 3000};

    std::cout << (solution(8, 15000, array_a1) == "2,1,5") << std::endl;
    std::cout << (solution(8, 15000, array_a2) == "2,4,8") << std::endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值