代码思路
代码主要解决的问题是:在给定的章节字数数组中,找到一个连续的子数组,使得该子数组的总字数不超过 k,并且在这个子数组中,优质章节的数量最多。优质章节的定义是:除了第一章和最后一章,任何字数多于前后章节的章节。
1. 初始化
- 首先定义了一个
f数组,用于标记哪些章节是优质章节。如果第i章是优质章节,则f[i] = 1,否则f[i] = 0。 - 通过遍历数组
a,判断每个章节是否为优质章节,并将其结果存储在f数组中。
2. 前缀和
- 定义了一个
s数组,用于存储字数的前缀和。s[i]表示从第 0 章到第i章的总字数。 - 通过遍历数组
a,计算前缀和并存储在s数组中。
3. 滑动窗口
- 使用了一个滑动窗口(双指针)技术来找到满足条件的子数组。
- 通过两个指针
l和r来表示当前窗口的左右边界。 - 通过移动右指针
r来扩展窗口,并通过移动左指针l来确保窗口内的总字数不超过k。 - 在每次扩展窗口时,计算当前窗口内的优质章节数量,并更新最大优质章节数量及其对应的窗口边界。
4. 结果输出
- 将最终的结果格式化为字符串,并返回。
前置知识点
1. 前缀和
前缀和是一种常用的数据结构,用于快速计算数组中某个区间的和。通过预先计算前缀和数组,可以在常数时间内计算任意区间的和。
vector<int> s(n, 0);
s[0] = a[0];
for(int i = 1; i < n; i++) {
s[i] = s[i - 1] + a[i];
}
2. 滑动窗口(双指针)
滑动窗口是一种常用的算法技巧,用于在数组或链表中找到满足特定条件的子数组或子序列。通过维护两个指针(通常称为左指针和右指针),可以在一次遍历中找到所有满足条件的子数组。
int l = 0;
for(int r = 0; r < n; r++) {
while(s[r] - (l ? s[l - 1] : 0) > k) l++;
// 在这里处理当前窗口
}
总结
代码通过前缀和和滑动窗口技术,有效地解决了在给定字数限制下找到最多优质章节的问题。理解前缀和、滑动窗口和数组操作是理解这段代码的关键。
完整代码
注意,下面的代码无法直接用于提交,为什么呢?
因为这个题目明显答案不唯一,然后题目没有 spj!
std::string solution(int n, int k, std::vector<int> a) {
// Please write your code here
vector<int> f(n, 0);
for(int i = 1 ; i < n - 1 ; i ++)
if(a[i] > a[i - 1] && a[i] > a[i + 1])
f[i] = 1;
vector<int> s(n, 0);
s[0] = a[0];
for(int i = 1 ; i < n ; i ++)
s[i] = s[i - 1] + a[i], f[i] += f[i - 1];
int l = 0;
int maxv = 0, L, R;
for(int r = 0 ; r < n ; r ++) {
while(s[r] - (l ? s[l - 1] : 0) > k) l ++;
if(l < r) {
int c = f[r] - (l ? f[l - 1] : 0);
if(maxv < c) {
maxv = c;
L = l, R = r;
}
}
}
string res = to_string(maxv) + ',' + to_string(L + 1) + ',' + to_string(R + 1);
cout << res << endl;
return res;
}