Files
leetcode-master/problems/kamacoder/0155.最小化频率的删除代价.md
programmercarl 574cef48b3 Update
2024-08-29 20:39:18 +08:00

3.8 KiB
Raw Blame History

最小化频率的删除代价

题目链接

计数和排序:

  • 使用 map 或 unordered_map 对数组 a 中每个元素出现的次数进行统计。
  • 将统计结果存入一个 vector<pair<int, int>>,其中 pair 的第一个元素是元素的出现次数,第二个元素是元素本身。
  • 按出现次数从大到小排序这个 vector。

确定最小 f(a)

  • 从最大出现次数开始尝试减少 f(a)。为此,从最高频次的元素开始逐步向下考虑较少出现的元素,计算达到更低 f(a) 所需删除的元素数量。
  • 使用一个累加器 count 来记录需要删除的元素数量,直到这个数量超过允许的最大删除数量 k 或恰好等于 k。在此过程中尽量使 f(a) 达到最小。

计算达到 f(a) 的代价:

  • 计算完成后,需要确定达到最小 f(a) 的确切代价。首先,为每个元素确定在不超过 k 的前提下可以删除的最大数量,以使得 f(a) 最小。
  • 对于每个元素,如果它的数量超过了新的 f(a),则计算减少到 f(a) 所需删除的具体元素数,记录下来。

计算具体删除代价:

  • 遍历原数组,对于每个需要删除的元素,根据其位置累加删除代价。每删除一个元素,相应地减少其在删除列表中的计数。当某元素需要删除的数量减至 0 时,从删除列表中移除该元素。

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

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

    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    unordered_map<int, int> umap;  // 使用map来统计每个元素的出现频率
    for (int i = 0; i < n; ++i) {
        umap[a[i]]++;  // 统计每个元素的出现次数
    }

    vector<pair<int, int>> table;
    for (auto& pair : umap) {
        table.push_back({pair.second, pair.first});  // 将元素和其频率作为一个pair放入table中
    }

    sort(table.begin(), table.end(), greater<>());  // 将table按照频率从大到小排序

    int count = 0;  // 用来计算已经删除的元素总数
    int minVal = table[0].first;  // 从最高频率开始
    for (int i = 0; i < table.size(); ++i) {
        int freq = table[i].first;
        count += (minVal - freq) * i;  // 累加删除元素的代价
        if (count > k) break;  // 如果超过了k停止循环
        else if (count == k) {
            minVal = freq;
            break;
        } else minVal = freq;
    }
    if (count < k) {
        int addDel = (k - count) / table.size();  // 如果删除的代价还没达到k计算还可以进一步减少的频率
        minVal -= addDel;  // 减少相应的频率
    }

    if (minVal < 0) {
        minVal = 0;  // 确保最小频率值不小于0
    }

    unordered_map<int, int> deleteList;  // 用来存储需要删除的元素及其数量
    for (auto& elem : table) {
        int num = elem.first;
        int ind = elem.second;
        if (num > minVal) {
            deleteList[ind] = num - minVal;  // 如果元素频率大于最小值,计算需要删除的数量
        } else {
            break;
        }
    }

    int cost = 0;  // 计算总的删除代价
    for (int i = 0; i < n; ++i) {
        if (deleteList.find(a[i]) != deleteList.end()) {
            cost += i + 1;  // 删除的代价是元素的索引+1
            deleteList[a[i]]--;  // 删除一个元素
            if (deleteList[a[i]] == 0) {
                deleteList.erase(a[i]);  // 如果元素已经全部删除,从列表中移除
                if (deleteList.empty()) {
                    break;  // 如果没有元素需要删除了,结束循环
                }
            }
        }
    }

    cout << minVal << " " << cost << endl;
    return 0;
}