题目描述
区块链底层存储是一个链式文件系统,由顺序的N个文件组成,每个文件的大小不一,依次为F1,F2,…,Fn。随着时间的推移,所占存储会越来越大。
云平台考虑将区块链按文件转储到廉价的SATA盘,只有连续的区块链文件才能转储到SATA盘上,且转储的文件之和不能超过SATA盘的容量。
假设每块SATA盘容量为M,求能转储的最大连续文件之和。
输入描述
第一行为SATA盘容量M,1000 ≤ M ≤ 1000000
第二行为区块链文件大小序列F1,F2,…,Fn。其中 1 ≤ n ≤ 100000,1 ≤ Fi ≤ 500
输出描述
求能转储的最大连续文件大小之和
用例
输入 | 1000 100 300 500 400 400 150 100 |
输出 | 950 |
说明 | 最大序列和为950,序列为[400,400,150] |
输入 | 1000 100 500 400 150 500 100 |
输出 | 1000 |
说明 | 最大序列和为1000,序列为[100,500,400] |
题目解析
由于本题需要求解最大连续文件大小之和,因此可以考虑使用双指针+滑动窗口来解题。
本题的滑动窗口的左边界l,右边界r的运动逻辑如下:
- 如果滑动窗口内部和 < m,则r++
- 如果滑动窗口内部和 > m,则l++
- 如果滑动窗口内部和 = m,则已得到最大值,直接返回m即可。
在计算滑动窗口内部和的过程中,如果r++,则说明内部和可能会增大产生最大值,因此我们需要在r++时,判断并保留最大值。
JavaScript算法源码
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const lines = [];
rl.on("line", (line) => {
lines.push(line);
if (lines.length === 2) {
const m = lines[0] - 0;
const F = lines[1].split(" ").map(Number);
console.log(getResult(m, F));
lines.length = 0;
}
});
function getResult(m, F) {
let l = 0,
r = 0;
let n = F.length;
let sum = 0;
let max = 0;
while (r < n) {
// 尝试右指针右移一下的新和(注意初始时右指针右移后指向0)
const newSum = sum + F[r];
// 如果新和超过了m,即SATA盘容量,则右指针不能右移,并且还需要左指针右移来减少旧和
if (newSum > m) {
sum -= F[l++]; // 左指针右移只会减少旧和,因此不会产生最大值
}
// 如果新和小于m,则当前尝试的右指针右移可行,因此 sum += F[r],并且我们下一步还可以继续尝试让右指针右移,即r++
else if (newSum < m) {
sum += F[r++];
max = Math.max(sum, max); // 右指针右移时会增加旧和,因此可能会产生最大值
}
// 如果新和等于m,那么说明已经找到了一个容量和SATA盘相同的连续文件大小,即此时已经是最大值了,可以直接返回
else {
return m;
}
}
return max;
}
Java算法源码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = Integer.parseInt(sc.nextLine());
Integer[] f =
Arrays.stream(sc.nextLine().split(" ")).map(Integer::parseInt).toArray(Integer[]::new);
System.out.println(getResult(m, f));
}
public static int getResult(int m, Integer[] f) {
int l = 0, r = 0;
int sum = 0, max = 0;
int n = f.length;
while (r < n) {
// 尝试右指针右移一下的新和(注意初始时右指针右移后指向0)
int newSum = sum + f[r];
// 如果新和超过了m,即SATA盘容量,则右指针不能右移,并且还需要左指针右移来减少旧和
if (newSum > m) {
sum -= f[l++]; // 左指针右移只会减少旧和,因此不会产生最大值
}
// 如果新和小于m,则当前尝试的右指针右移可行,因此 sum += F[r],并且我们下一步还可以继续尝试让右指针右移,即r++
else if (newSum < m) {
sum += f[r++];
max = Math.max(sum, max); // 右指针右移时会增加旧和,因此可能会产生最大值
}
// 如果新和等于m,那么说明已经找到了一个容量和SATA盘相同的连续文件大小,即此时已经是最大值了,可以直接返回
else {
return m;
}
}
return max;
}
}
Python算法源码
m = int(input())
f = list(map(int, input().split()))
def getResult(m, f):
l = 0
r = 0
n = len(f)
sum = 0
maxV = 0
while r < n:
# 尝试右指针右移一下的新和(注意初始时右指针右移后指向0)
newSum = sum + f[r]
# 如果新和超过了m,即SATA盘容量,则右指针不能右移,并且还需要左指针右移来减少旧和
if newSum > m:
# 左指针右移只会减少旧和,因此不会产生最大值
sum -= f[l]
l += 1
# 如果新和小于m,则当前尝试的右指针右移可行,因此 sum += F[r],并且我们下一步还可以继续尝试让右指针右移,即r++
elif newSum < m:
sum += f[r]
r += 1
maxV = max(sum, maxV) # 右指针右移时会增加旧和,因此可能会产生最大值
# 如果新和等于m,那么说明已经找到了一个容量和SATA盘相同的连续文件大小,即此时已经是最大值了,可以直接返回
else:
return m
return maxV
print(getResult(m, f))
免责声明:
1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文
评论0