内存冷热标记 - 华为OD统一考试(C卷)

OD统一考试(C卷)

分值: 100分

题解: Java / Python / C++

alt

题目描述

现代计算机系统通常存在多级的存储设备,针对海量的 wordload 的优化的一种思路是将热点内存页优化先放到快速存储层级,这就需要对内存页进行冷热标记。

一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,要实现基于频次的冷热标记。内存页使用页框号作为标识。

输入描述

第一行输入为 N, 表示访存序列的记录条数, 0 < N ≤ 10000。

第二行为访问内存序列,空格间隔的 N 个内存页框号,页面号范围 0 ~ 65535,同一个页框号可能重复出现,出现的次数即为对应框号的频次。

第三行为热内存的频次阈值 T ,正整数范围 1 ≤ T ≤ 10000。

输出描述

第一行为输出标记为热内存的内存页个数,如果没有被标记为热内存的,则输出 0。

如果第一行大于 0,则接下来按照访问频次降序输出内存页框号,一行一个,频次一样的页框号,页框号小的排前面。

示例1

输入:
10
1 2 1 2 1 2 1 2 1 2
5

输出:
2
1
2

说明:
内存页 1 和内存页 2 均被访问了5 次,达到了阈值5 ,因此热内存页有2个。内存页1 和内存页 2 的访问频次相等,页框号小的排前面。

示例2

输入:
5
1 2 3 4 5
3

输出:
0

说明:
从访问跟踪里面访问频次没有超过 3 的,因此热内存个数为 0。

题解

这道题目首先需要统计每个内存页的访问频次,然后根据设定的阈值判断是否为热内存。接着,需要按照访问频次降序进行排序,同时对于频次相同的内存页,要按照页框号升序排序。

以下是解题思路的详细步骤:

  1. 使用一个Map(Java和Python)或者unordered_map(C++)来统计每个内存页的访问频次。键为页框号,值为对应的频次。
  2. 遍历输入的内存访问序列,更新频次统计。
  3. 遍历频次统计,将频次大于等于设定阈值的内存页加入一个列表。
  4. 对列表进行自定义排序,首先按照访问频次降序排序,然后在频次相同的情况下按照页框号升序排序。
  5. 输出结果,首先输出热内存的个数,然后按照排序后的顺序输出内存页框号。

Java

import java.util.*;
/**
 * @author code5bug
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();

        // 内存页访问次数
        Map<Integer, Integer> cnt = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int x = scanner.nextInt();
            cnt.put(x, cnt.getOrDefault(x, 0) + 1);
        }

        int t = scanner.nextInt();

        // 热内存(频次大于等于阈值的内存页)
        List<Map.Entry<Integer, Integer>> vcnt = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : cnt.entrySet()) {
            if (entry.getValue() >= t) {
                vcnt.add(entry);
            }
        }

        // 自定义排序
        Collections.sort(vcnt, (a, b) -> {
            if (!a.getValue().equals(b.getValue())) {
                return Integer.compare(b.getValue(), a.getValue());
            } else {
                return Integer.compare(a.getKey(), b.getKey());
            }
        });

        // 打印结果
        System.out.println(vcnt.size());
        for (Map.Entry<Integer, Integer> entry : vcnt) {
            System.out.println(entry.getKey());
        }
    }
}

Python

from collections import defaultdict

n = int(input())

# 内存页访问次数
cnt = defaultdict(int)
for x in map(int, input().split()):
    cnt[x] += 1

t = int(input())

# 热内存(频次大于等于阈值的内存页)
vcnt = [(key, value) for key, value in cnt.items() if value >= t]

# 自定义排序
vcnt.sort(key=lambda x: (-x[1], x[0]))

# 打印结果
print(len(vcnt))
for key, _ in vcnt:
    print(key)

C++

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, t;
    cin >> n;

    // 内存页访问次数
    unordered_map<int, int> cnt;
    for (int i = 0, x; i < n; i++) {
        cin >> x;
        cnt[x]++;
    }
    cin >> t;

    // 热内存(频次大于等于阈值的内存页)
    vector<pair<int, int>> vcnt;
    for (auto it : cnt) {
        if (it.second >= t) {
            vcnt.push_back(it);
        }
    }

    // 自定义排序
    sort(vcnt.begin(), vcnt.end(), [](pair<int, int> a, pair<int, int> b) {
        if (a.second != b.second) {
            return a.second > b.second;
        } else {
            return a.first < b.first;
        }
    });

    // 打印结果
    cout << vcnt.size() << endl;
    for (auto it : vcnt) {
        cout << it.first << endl;
    }

    return 0;
}

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏

#面经##春招##秋招##校招##华为#
全部评论
怎么进行具体的刷这道题目
点赞 回复 分享
发布于 2024-06-06 11:22 上海
索引为页号,值为出现的频次,遍历输出判断是否达到预热,有就输出,预热次数加一。 唯一的遗憾就是需要创建一个很大的数组 int[] h = new int[65535];
点赞 回复 分享
发布于 2024-04-11 15:37 四川

相关推荐

点赞 评论 收藏
分享
评论
3
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务