#P2355. 第3题-存储
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 404
            Accepted: 96
            Difficulty: 6
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2023年10月11日-国内
                              
                      
          
 
- 
                        算法标签>哈希表          
 
第3题-存储
题面描述
塔子哥正在研究虚拟化内存,并希望实现一个地址范围为32G的内存机制,支持数据的读写和清空操作。输入包括多个指令,格式为“Command Address Length Data”,其中Command可以是Read、Write或Clear,Address是64位无符号十六进制数,Length是64位无符号十进制数,Data是以字节流形式表示的十六进制数据。输出只针对Read指令,返回相应地址的数据,若参数不合法则不输出。示例输入包括Write、Read和Clear指令,程序需要根据指令处理内存数据,并确保符合题目要求。
思路:哈希表模拟
观察数据规模,存储的数据量不超过16MB,即为224,因此可以使用哈希表来存储
- 执行
Clear操作时,清空哈希表即可 - 执行
Write操作时,按位置写入每个字节 - 执行
Read操作时,首先需要判断哈希表中是否存在,如果不存在,使用00代替, 
每次执行Write和Read操作时,都需要判断输入的长度len是否在合法范围,len的合法范围为0≤len≤234
时间复杂度
O(nlogn)
代码
C++
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
// 使用哈希表存储地址和对应的数据
unordered_map<unsigned long long, string> m;
int main() {
    int n; // 指令数量
    cin >> n; // 输入指令的数量
    
    for (int i = 0; i < n; i++) {
        string cmd, data; // cmd为命令,data为数据
        unsigned long long address, length; // address为地址,length为长度
        cin >> cmd; // 读取命令
        
        if (cmd == "Write") {
            // 处理Write命令
            cin >> hex >> address >> dec >> length; // 读取地址(十六进制)和长度(十进制)
            cin >> data; // 读取数据(十六进制字符串)
            
            // 如果提供的数据长度小于指定长度,补零
            if (data.size() < length * 2) {
                string s(length * 2 - data.size(), '0'); // 生成补零字符串
                data += s; // 在data后添加补零
            }
            // 将数据写入对应地址
            m[address] = data;
        } else if (cmd == "Read") {
            // 处理Read命令
            cin >> hex >> address >> dec >> length; // 读取地址和长度
            
            // 判断地址是否存在
            if (m.find(address) != m.end()) {
                string data = m[address]; // 从哈希表中获取数据
                // 如果请求的长度大于存储的数据长度,进行补零
                if (length * 2 > data.size()) {
                    data += string(length * 2 - data.size(), '0'); // 追加补零
                } else {
                    // 截取到指定长度
                    data = data.substr(0, length * 2);
                }
                cout << data << endl; // 输出读取的数据
            } else {
                // 如果地址不存在,返回全0
                cout << string(length * 2, '0') << endl; // 返回补零
            }
        } else if (cmd == "Clear") {
            // 处理Clear命令
            m.clear(); // 清空哈希表
        }
    }
}
python代码
import sys
from collections import defaultdict
# 主要的处理函数
def solution(lines):
    n = len(lines)  # 获取输入行数
    rec = defaultdict(str)  # 使用defaultdict来存储地址到数据的映射,默认值为空字符串
    # 遍历每一行指令
    for line in lines:
        strs = line.split()  # 将每行指令按空格分割成字符串列表
        
        if strs[0] == 'Clear':
            # 如果指令是Clear,清空记录
            rec = defaultdict(str)  # 重新初始化defaultdict
            
        elif strs[0] == 'Write':
            # 如果指令是Write,处理写入操作
            add = strs[1]  # 获取地址
            if len(add) > 66:  # 如果地址长度超过66字符,跳过该指令
                continue
            
            length = int(strs[2])  # 获取写入的长度
            if length > 16 * 1024 * 1024:  # 如果长度超过16MB,跳过该指令
                continue
            
            data = strs[3]  # 获取要写入的数据
            if len(data) > length * 2:  # 如果数据长度大于指定长度
                data = data[:length * 2]  # 截取数据至指定长度
            
            rec[add] = data  # 将数据写入到对应的地址
            
        elif strs[0] == 'Read':
            # 如果指令是Read,处理读取操作
            add = strs[1]  # 获取地址
            if len(add) > 66:  # 如果地址长度超过66字符,跳过该指令
                continue
            
            length = int(strs[2])  # 获取读取的长度
            data = rec[add]  # 从记录中获取对应地址的数据
            
            if len(data) > length * 2:  # 如果获取的数据长度超过读取长度
                print(data[:length * 2])  # 输出截取的结果
            else:
                # 如果获取的数据长度小于读取长度,输出数据并补零
                print(data + ''.join(['0' for _ in range(length * 2 - len(data))]))  # 输出补零的结果
# 主函数
def main():
    n = int(input())  # 读取指令的数量
    lines = []  # 创建一个空列表来存储输入行
    for _ in range(n):
        lines.append(input())  # 逐行读取指令并添加到列表中
    
    solution(lines)  # 调用处理函数
# 执行主函数
main()
Java代码
import java.util.Arrays; // 导入Arrays类用于数组操作
import java.util.Scanner; // 导入Scanner类用于输入
import java.util.stream.IntStream; // 导入IntStream类用于流操作
public class Main {
    @SuppressWarnings({ "resource" }) // SuppressWarnings用于抑制警告
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in); // 创建Scanner对象,用于读取输入
        String[] strs = sc.nextLine().split(","); // 读取一行输入并按逗号分割成字符串数组
        int[] arr = Arrays.stream(strs).mapToInt(Integer::parseInt).toArray(); // 将字符串数组转换为整数数组
        Arrays.sort(arr); // 对整数数组进行排序
        int[] sum = new int[arr.length]; // 创建一个数组用于存储从当前索引到末尾的和
        int res = 0; // 初始化结果变量
        
        // 遍历数组,计算从当前索引到末尾的和
        for (int i = 0; i < arr.length; i++) {
            // 计算从索引i到末尾的和,并存储在sum[i]
            sum[i] = IntStream.of(Arrays.copyOfRange(arr, i, arr.length)).sum();
            // 如果当前和大于0,累加到结果
            if (sum[i] > 0) {
                res = res + sum[i]; // 更新结果
            }
        }
        // 输出最终结果
        System.out.println(res);
    }
}
        题目描述
最近小明正在研究什么是虚拟化内存,于是小明想自己亲自动手试一试,你能帮助他吗?
实现一个地址范围为32G,可在范围内任意位置进行数据读写的虚拟化内存机制,数据默认清零。 功能:
- 读写任意地址数据;
 - 往任意地址写入任意数据;
 - 清空数据,并释放内存;
 
PS:一个地址空间存一个数据,各地址空间独立
输入描述
输入格式:Command Address Length Data
1、Command为Read、Write、Clear之一
2、Address采用64位无符号十六进制数,全大写
3、Length采用64位无符号十进制数,单位为“字节”
4、Data采用字节流(2个16进制数表示一个Byte),全大写;
5、如果指定的Length大于实际给定的Data,需要程序自行未尾补0,小于则末尾截断
每条指令一行,一个用例输入可以是多条指令混合,只有Read指令有输出。
每个用倒保证指令、参数格式正确,但不保证参数范围,需要程序照题目规格要求自行校验,参数不合法,则对应的指令无效。
每个用例保证需要存储的总数据量最大不超过16MB。一个用例最多不超过500条指令。
例如(3表示有3条指令)
3
Write 0x100 7 001122AA
Read 0x100 4
Clear
输出描述
采用字节流(2个16进制数表示一个Byte),全大写
例如 001122AA
每条Read指令对应一行输出数据,如果指令给的参数不合法,对应的输出为空(不换行)。
样例
输入1
1
Read 0x100 4
输出1
00000000
说明
0x100地址空间未被写入数据,默认返回全0,一共4个字节
输入2
3
Write 0x100 8 00001122AABBCCDD
Read 0x100 12
Clear
输出2
00001122AABBCCDD00000000
说明
0x100地址,前8个字节被写入了有效数据00001122AABBCCDD,读取0x100地址12字节数据,后4个字节补齐默认数0,因此结果为00001122AABBCCDD00000000