【华为OD】区块链文件转储系统

文章目录

【华为OD】区块链文件转储系统

题目描述

区块链底层存储是一个链式文件系统,由顺序的 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]

解题思路

这是一个经典的最大连续子数组和问题的变种,需要在满足和不超过容量M的约束条件下,找到最大的连续子数组和。

我们可以使用两种方法来解决:

  1. 滑动窗口法:使用双指针维护一个滑动窗口,动态调整窗口大小
  2. 暴力枚举法:枚举所有可能的连续子数组,找到满足条件的最大和

解法一:滑动窗口法

滑动窗口是解决这类问题的最优方法,时间复杂度为O(n)。

Java实现

java 复制代码
import java.util.*;

public class Solution {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        scanner.nextLine(); // 消费换行符
        
        String[] fileStr = scanner.nextLine().split(" ");
        int[] files = new int[fileStr.length];
        for (int i = 0; i < fileStr.length; i++) {
            files[i] = Integer.parseInt(fileStr[i]);
        }
        
        int maxSum = 0;
        int left = 0;
        int currentSum = 0;
        
        for (int right = 0; right < files.length; right++) {
            currentSum += files[right];
            
            // 如果当前和超过容量,收缩左边界
            while (currentSum > M && left <= right) {
                currentSum -= files[left];
                left++;
            }
            
            // 更新最大和
            maxSum = Math.max(maxSum, currentSum);
        }
        
        System.out.println(maxSum);
    }
}

Python实现

python 复制代码
def solve():
    M = int(input())
    files = list(map(int, input().split()))
    
    max_sum = 0
    left = 0
    current_sum = 0
    
    for right in range(len(files)):
        current_sum += files[right]
        
        # 如果当前和超过容量,收缩左边界
        while current_sum > M and left <= right:
            current_sum -= files[left]
            left += 1
        
        # 更新最大和
        max_sum = max(max_sum, current_sum)
    
    print(max_sum)

solve()

C++实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;

int main() {
    int M;
    cin >> M;
    cin.ignore(); // 忽略换行符
    
    string line;
    getline(cin, line);
    istringstream iss(line);
    vector<int> files;
    int file;
    while (iss >> file) {
        files.push_back(file);
    }
    
    int maxSum = 0;
    int left = 0;
    int currentSum = 0;
    
    for (int right = 0; right < files.size(); right++) {
        currentSum += files[right];
        
        // 如果当前和超过容量,收缩左边界
        while (currentSum > M && left <= right) {
            currentSum -= files[left];
            left++;
        }
        
        // 更新最大和
        maxSum = max(maxSum, currentSum);
    }
    
    cout << maxSum << endl;
    return 0;
}

解法二:暴力枚举法

虽然时间复杂度较高O(n²),但思路简单直观,适合理解问题本质。

Java实现

java 复制代码
import java.util.*;

public class Solution2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        scanner.nextLine();
        
        String[] fileStr = scanner.nextLine().split(" ");
        int[] files = new int[fileStr.length];
        for (int i = 0; i < fileStr.length; i++) {
            files[i] = Integer.parseInt(fileStr[i]);
        }
        
        int maxSum = 0;
        
        // 枚举所有可能的起始位置
        for (int i = 0; i < files.length; i++) {
            int currentSum = 0;
            // 从起始位置开始累加
            for (int j = i; j < files.length; j++) {
                currentSum += files[j];
                if (currentSum <= M) {
                    maxSum = Math.max(maxSum, currentSum);
                } else {
                    break; // 超过容量,停止扩展
                }
            }
        }
        
        System.out.println(maxSum);
    }
}

Python实现

python 复制代码
def solve_brute_force():
    M = int(input())
    files = list(map(int, input().split()))
    
    max_sum = 0
    
    # 枚举所有可能的起始位置
    for i in range(len(files)):
        current_sum = 0
        # 从起始位置开始累加
        for j in range(i, len(files)):
            current_sum += files[j]
            if current_sum <= M:
                max_sum = max(max_sum, current_sum)
            else:
                break  # 超过容量,停止扩展
    
    print(max_sum)

solve_brute_force()

C++实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;

int main() {
    int M;
    cin >> M;
    cin.ignore();
    
    string line;
    getline(cin, line);
    istringstream iss(line);
    vector<int> files;
    int file;
    while (iss >> file) {
        files.push_back(file);
    }
    
    int maxSum = 0;
    
    // 枚举所有可能的起始位置
    for (int i = 0; i < files.size(); i++) {
        int currentSum = 0;
        // 从起始位置开始累加
        for (int j = i; j < files.size(); j++) {
            currentSum += files[j];
            if (currentSum <= M) {
                maxSum = max(maxSum, currentSum);
            } else {
                break; // 超过容量,停止扩展
            }
        }
    }
    
    cout << maxSum << endl;
    return 0;
}

算法分析

时间复杂度

  • 滑动窗口法:O(n),每个元素最多被访问两次
  • 暴力枚举法:O(n²),需要枚举所有可能的子数组

空间复杂度

  • 两种方法的空间复杂度都是O(n),主要用于存储输入数组

推荐方案

对于本题的数据规模(n ≤ 100000),强烈推荐使用滑动窗口法,因为:

  1. 时间复杂度更优,能够在规定时间内通过所有测试用例
  2. 代码简洁,逻辑清晰
  3. 是解决此类问题的标准算法

总结

区块链文件转储系统问题本质上是一个约束条件下的最大连续子数组和问题。通过滑动窗口技术,我们可以高效地解决这个问题。这种方法在处理连续子数组相关问题时非常有用,是算法面试中的常考知识点。

相关推荐
塔中妖2 小时前
【华为OD】Linux发行版的数量
linux·算法·华为od
熊文豪2 小时前
【华为OD】阿里巴巴找黄金宝箱
算法·华为od
塔中妖2 小时前
【华为OD】5G网络建设
网络·5g·华为od
bestadc3 小时前
LeetCode 几道 Promises 和 Time 的题目
javascript·算法·leetcode
墨染点香3 小时前
LeetCode 刷题【71. 简化路径】
算法·leetcode·职场和发展
知彼解己3 小时前
【算法】四大基础数据结构
数据结构·算法
老一岁3 小时前
希尔排序详解
数据结构·算法·排序算法
lifallen3 小时前
KafkaStreams 计算图节点设计:ProcessorNode、SourceNode、SinkNode
java·数据结构·算法·kafka·apache
索迪迈科技3 小时前
java后端工程师进修ing(研一版‖day42)
java·开发语言·学习·算法