c++流之sstream/堆or优先队列的应用[1]

news2025/6/2 8:22:30

目录

c++流之sstream

解释

注意事项

215.数据流的第k'大

问题分析

修正代码

主要修改点

优先队列的比较规则

代码中的比较逻辑

为什么这样能维护第 k 大元素?

举个例子

总结

Python 实现(使用heapq库)

Java 实现(使用PriorityQueue)

复杂度分析

347.前k大频率数字

复杂度分析:

代码解释:

复杂度分析:

具体规则

为什么代码中用小顶堆?

示例验证

输出结果

总结

 


c++流之sstream

要使用 std::istringstream,你需要包含 <sstream> 头文件。 

#include <iostream>
#include <sstream> // 包含 sstream 头文件

int main() {
    std::string input = "push 15";
    int number;

    // 使用 std::istringstream 从字符串中提取数字
    std::istringstream iss(input);
    std::string command;
    iss >> command >> number; // 读取命令和数字

    // 输出提取的数字
    std::cout << "Command: " << command << std::endl;
    std::cout << "Extracted number: " << number << std::endl;

    return 0;
}

引用

解释

  1. 包含头文件:确保包含了 <sstream> 头文件,以便使用 std::istringstream
  2. 使用 std::istringstream:创建一个 std::istringstream 对象,并将输入字符串传递给它。
  3. 提取数据:使用 >> 运算符从 std::istringstream 中提取数据。

注意事项

  • std::istringstream 是一个字符串输入流,可以用于从字符串中读取数据。
  • >> 运算符用于从流中提取数据,类似于从标准输入中读取数据。

通过这种方式,你可以从字符串中提取命令和数字。

事实上 这样用到qingwen还是不行.为什么了?自己造字符串能读,他给的就不行.

我的代码

   int k;
    cin>>n;cin>>k;
    string a;string command;int m;
    for(int i=0;i<n;i++)
       {         cin >> a;
        istringstream iss(a);
        iss >> command >> m;
       cout<<command<<m;hp[i+1]=m;}
    // for(int i=n/2;i>=1;i--)
    // downAdjust(i,n);

    for(int i=0;i<n;i++)
        cout<<hp[i+1]<<(i==n-1?"":" ");

输入数据

 

7 2 Push 1 Print Push 3 Print Push 7 Push 6 Print

你的输出

 

Push010Print0Push030Print0Push00 0 0 0 0 0 0

真不知道为什么,自己写了push 15 是可以识别的

换成他的输入a瞬间就不行了 

老老实实scanf吧.... 

215.数据流的第k'大

#include <iostream> #include <vector> #include <string> #include <queue> using namespace std; int main() { priority_queue<int, vector<int>, greater<int> > q; int n, k, x; cin >> n >> k; string action; for (int i = 0; i < n; i++) { cin >> action; if (action == "Print") { if (q.size() >= k) { cout << q.top() << endl; } else { cout << -1 << endl; } } else if (action == "Push") { cin >> x; q.push(x); if (q.size() > k) { q.pop(); } } } return 0; }这对吗

你的代码基本逻辑是正确的,但有一个小问题需要修正。

问题分析

  1. 功能逻辑:代码使用最小堆(优先队列)维护当前最大的 k 个元素。每次 Push 操作时,如果队列大小超过 k,则弹出最小元素;每次 Print 操作时,如果队列中有至少 k 个元素,则输出堆顶元素(即第 k 大元素),否则输出 - 1。

  2. 潜在问题:当 k=0 时,Push 操作会导致队列大小超过 k(变为 1),触发 pop (),但此时队列实际容量应为 0,因此不应该执行 push 操作。

修正代码

以下是修正后的完整代码:

cpp

运行

#include <iostream>
#include <vector>
#include <string>
#include <queue>
using namespace std;

int main() {
    priority_queue<int, vector<int>, greater<int>> q;
    int n, k, x;
    cin >> n >> k;
    string action;
    for (int i = 0; i < n; i++) {
        cin >> action;
        if (action == "Print") {
            if (q.size() >= k) {
                cout << q.top() << endl;
            } else {
                cout << -1 << endl;
            }
        } else if (action == "Push") {
            cin >> x;
            // 关键修改:只有当队列当前元素不足k时才push
            if (q.size() < k) {
                q.push(x);
            } else if (k > 0 && x > q.top()) {
                // 如果队列已满且新元素比堆顶大,则替换堆顶
                q.pop();
                q.push(x);
            }
        }
    }
    return 0;
}

主要修改点

  1. Push 操作优化

    • 增加判断 if (q.size() < k) 确保队列不会超过 k 个元素
    • 增加 k > 0 检查防止 k=0 时的非法操作
    • 当队列已满时,仅当新元素大于堆顶元素才替换堆顶
  2. 边界处理

    • 正确处理 k=0 的情况(此时 Print 始终输出 - 1,Push 不执行任何操作)
    • 当 k=1 时,队列始终维护最大值

这个修正后的代码能够正确处理所有边界情况,包括 k=0 和 k=1 的特殊情况,以及元素替换逻辑。

为什么他能用队列维护最小堆?没看到他在哪大小比较了

在这段代码中,priority_queue 的比较逻辑是通过模板参数 greater<int> 指定的,这决定了队列的排序规则。让我解释一下:

优先队列的比较规则

在 C++ 中,priority_queue 的默认比较规则是 less<T>(大顶堆),但这段代码使用了:

cpp

运行

priority_queue<int, vector<int>, greater<int>> q;

这里的 greater<int> 是一个比较函数对象,它定义了元素间的顺序关系:

  • greater<int> 会让较小的元素排在队列前面(升序)
  • 因此堆顶元素始终是当前队列中的最小值
  • 这就实现了一个最小堆的功能

代码中的比较逻辑

虽然代码里没有显式的比较语句,但比较逻辑隐藏在 greater<int> 中:

  • 每次 push(x) 时,队列会自动调整,确保堆顶是最小值
  • 当队列大小超过 k 时,pop() 操作会移除当前最小值(堆顶)
  • 因此队列始终维护着最大的 k 个元素,堆顶是这 k 个中的最小值

为什么这样能维护第 k 大元素?

  • 假设我们有一个动态的数据流,每次插入元素后:
    1. 如果队列未满(size < k),直接插入
    2. 如果队列已满(size == k),且新元素比堆顶大:
      • 弹出堆顶(当前最小值)
      • 插入新元素
    3. 这样队列始终保存着最大的 k 个元素,而堆顶就是第 k 大元素

举个例子

假设 k=3,数据流是 5, 3, 7, 2, 8

  1. 插入 5:队列 [5]
  2. 插入 3:队列 [3, 5]
  3. 插入 7:队列 [3, 5, 7](堆顶 3 是当前第 3 大)
  4. 插入 2:2 比堆顶 3 小,丢弃,队列仍为 [3, 5, 7]
  5. 插入 8:8 比堆顶 3 大,弹出 3,插入 8,队列变为 [5, 7, 8]
  6. 最终队列保存最大的 3 个元素,堆顶 5 就是第 3 大元素

总结

比较逻辑由 greater<int> 隐式实现,它确保:

  • 堆顶始终是队列中的最小值
  • 通过限制队列大小为 k,堆顶就是第 k 大元素

这种方法巧妙地利用了最小堆的特性,避免了显式排序,时间复杂度为 O (log k),非常高效。

 

要解决 “数据流中的第 K 大元素” 问题,通常可以使用 ** 最小堆(小顶堆)** 来高效实现。这种方法在维护一个大小为 K 的堆时,能保证堆顶元素始终是第 K 大的元素。以下是具体的实现思路:

  1. 初始化堆:创建一个最小堆,并在添加元素时保持堆的大小不超过 K。
  2. 添加元素:对于每个新元素,如果堆的大小小于 K,则直接加入堆;否则,比较新元素与堆顶元素的大小,若新元素更大,则替换堆顶元素并调整堆。

以下是使用 Python 和 Java 实现的代码示例:

Python 实现(使用heapq库)

python

运行

import heapq

class KthLargest:
    def __init__(self, k: int, nums: list[int]):
        self.k = k
        self.heap = nums
        heapq.heapify(self.heap)  # 将列表转换为最小堆
        # 保持堆的大小为k
        while len(self.heap) > k:
            heapq.heappop(self.heap)

    def add(self, val: int) -> int:
        if len(self.heap) < self.k:
            heapq.heappush(self.heap, val)
        elif val > self.heap[0]:  # 堆顶元素是当前第k大的元素
            heapq.heapreplace(self.heap, val)
        return self.heap[0]  # 返回堆顶元素,即第k大的元素

# 示例用法
kth_largest = KthLargest(3, [4, 5, 8, 2])
print(kth_largest.add(3))  # 输出: 4
print(kth_largest.add(5))  # 输出: 5

Java 实现(使用PriorityQueue

java

import java.util.PriorityQueue;

class KthLargest {
    private PriorityQueue<Integer> minHeap;
    private int k;

    public KthLargest(int k, int[] nums) {
        this.k = k;
        minHeap = new PriorityQueue<>(k);
        for (int num : nums) {
            add(num);
        }
    }

    public int add(int val) {
        if (minHeap.size() < k) {
            minHeap.offer(val);
        } else if (val > minHeap.peek()) {
            minHeap.poll();
            minHeap.offer(val);
        }
        return minHeap.peek();
    }

    public static void main(String[] args) {
        KthLargest kthLargest = new KthLargest(3, new int[]{4, 5, 8, 2});
        System.out.println(kthLargest.add(3)); // 输出: 4
        System.out.println(kthLargest.add(5)); // 输出: 5
    }
}

复杂度分析

  • 时间复杂度:初始化时为 O (n log k),每次添加操作为 O (log k)。
  • 空间复杂度:O (k),主要用于维护堆的大小。

这种方法通过最小堆动态维护数据流中的前 K 大元素,确保在处理海量数据时依然高效。

347.前k大频率数字

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

为了解决这个问题,我们可以使用哈希表统计元素频率,然后结合最小堆来维护前 k 高的元素。以下是具体的实现步骤:

  1. 统计元素频率:使用哈希表记录每个元素的出现次数。
  2. 维护最小堆:遍历哈希表,使用最小堆维护当前频率最高的 k 个元素。如果堆的大小超过 k,则移除频率最小的元素。
  3. 提取结果:最终堆中的元素即为频率前 k 高的元素。

下面是实现代码:

python

运行

from collections import Counter
import heapq

def topKFrequent(nums, k):
    # 统计每个元素的频率
    count = Counter(nums)
    
    # 使用最小堆维护前k个高频元素
    heap = []
    for num, freq in count.items():
        # 若堆的大小小于k,直接添加
        if len(heap) < k:
            heapq.heappush(heap, (freq, num))
        # 否则比较当前频率与堆顶元素频率
        else:
            if freq > heap[0][0]:
                heapq.heappop(heap)
                heapq.heappush(heap, (freq, num))
    
    # 提取堆中的元素
    return [num for freq, num in heap]

# 示例测试
nums = [1,1,1,2,2,3]
k = 2
print(topKFrequent(nums, k))  # 输出: [1, 2]

复杂度分析:

  • 时间复杂度:O (n log k),其中 n 是数组的长度。遍历数组统计频率需要 O (n) 时间,每次堆操作需要 O (log k) 时间。
  • 空间复杂度:O (n),主要用于哈希表存储频率。

c++

cpp

运行

#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;

vector<int> topKFrequent(vector<int>& nums, int k) {
    // 统计每个元素的频率
    unordered_map<int, int> freq;
    for (int num : nums) {
        freq[num]++;
    }
    
    // 使用最小堆维护前k个高频元素
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> heap;
    for (auto& pair : freq) {
        heap.push({pair.second, pair.first});
        if (heap.size() > k) {
            heap.pop();
        }
    }
    
    // 提取堆中的元素
    vector<int> result(k);
    for (int i = k - 1; i >= 0; i--) {
        result[i] = heap.top().second;
        heap.pop();
    }
    return result;
}

代码解释:

  1. 统计频率:使用unordered_map统计每个元素的出现次数。
  2. 维护最小堆:遍历频率表,将元素按频率插入最小堆(优先队列)。当堆大小超过 k 时,弹出堆顶(最小频率元素)。
  3. 提取结果:堆中剩余的 k 个元素即为频率前 k 高的元素,按频率从低到高提取并反转。

复杂度分析:

  • 时间复杂度:O (n log k),其中 n 是数组长度。统计频率 O (n),堆操作 O (log k)。
  • 空间复杂度:O (n),主要用于哈希表存储频率。

优先队列元素是pair<int,int>我怎么知道它是按哪一个优先?

在 C++ 中,当优先队列(priority_queue)的元素类型是pair<int, int>时,默认的比较规则是按第一个元素降序排列。如果第一个元素相同,则按第二个元素降序排列。这是因为pair的比较运算符默认先比较第一个元素(first),再比较第二个元素(second)。

具体规则

  1. 默认比较规则(大顶堆):

    cpp

    运行

    priority_queue<pair<int, int>> heap; // 默认使用 less<pair<int, int>>
    
     
    • 堆顶元素是第一个元素(first)最大的 pair
    • 如果多个 pair 的第一个元素相同,则取第二个元素(second)最大的
  2. 自定义比较规则(小顶堆):

    cpp

    运行

    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> heap;
    
     
    • 堆顶元素是第一个元素(first)最小的 pair
    • 如果多个 pair 的第一个元素相同,则取第二个元素(second)最小的

为什么代码中用小顶堆?

在之前的 Top K 高频元素代码中,我们使用了小顶堆:

cpp

运行

priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> heap;

  • 元素类型pair<int, int> 中 first 是频率,second 是元素值
  • 比较规则greater 使堆按频率升序排列(频率小的在堆顶)
  • 作用:每次弹出频率最小的元素,最终堆中保留频率最大的 k 个元素

示例验证

以下代码验证优先队列对pair的排序规则:

cpp

运行

#include <iostream>
#include <queue>
using namespace std;

int main() {
    // 大顶堆(默认)
    priority_queue<pair<int, int>> maxHeap;
    maxHeap.push({3, 100}); // 频率3,元素100
    maxHeap.push({1, 200}); // 频率1,元素200
    maxHeap.push({3, 50});  // 频率3,元素50
    
    cout << "大顶堆顺序:" << endl;
    while (!maxHeap.empty()) {
        auto p = maxHeap.top();
        cout << "频率: " << p.first << ", 元素: " << p.second << endl;
        maxHeap.pop();
    }
    
    // 小顶堆
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> minHeap;
    minHeap.push({3, 100});
    minHeap.push({1, 200});
    minHeap.push({3, 50});
    
    cout << "\n小顶堆顺序:" << endl;
    while (!minHeap.empty()) {
        auto p = minHeap.top();
        cout << "频率: " << p.first << ", 元素: " << p.second << endl;
        minHeap.pop();
    }
    
    return 0;
}

输出结果

plaintext

大顶堆顺序:
频率: 3, 元素: 100
频率: 3, 元素: 50
频率: 1, 元素: 200

小顶堆顺序:
频率: 1, 元素: 200
频率: 3, 元素: 50
频率: 3, 元素: 100

总结

在 Top K 高频元素问题中:

  • 小顶堆按频率升序排列,堆顶是频率最小的元素
  • 通过限制堆的大小为 k,每次弹出最小频率元素,最终堆中保留的就是前 k 大频率元素

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAR ADC 比较器噪声分析(二)

SAR ADC的比较器是非常重要的模块&#xff0c;需要仔细设计。主要考虑比较器的以下指标&#xff1a; 1)失调电压 2)输入共模范围 3)比较器精度 4)传输延时 5)噪声 6)功耗 这里主要讲一下动态比较器的noise。 动态比较器一般用于高速SAR ADC中&#xff0c;且精度不会超过12bit…

机器学习Day5-模型诊断

实现机器学习算法的技巧。当我们训练模型或使用模型时&#xff0c;发现预测误差很 大&#xff0c;可以考虑进行以下优化&#xff1a; &#xff08;1&#xff09;获取更多的训练样本 &#xff08;2&#xff09;使用更少的特征 &#xff08;3&#xff09;获取其他特征 &#xff…

vscode一直连接不上虚拟机或者虚拟机容器怎么办?

1. 检查并修复文件权限 右键点击 C:\Users\20325\.ssh\config 文件&#xff0c;选择 属性 → 安全 选项卡。 确保只有你的用户账户有完全控制权限&#xff0c;移除其他用户&#xff08;如 Hena\Administrator&#xff09;的权限。 如果 .ssh 文件夹权限也有问题&#xff0c;同…

初学c语言21(文件操作)

一.为什么使用文件 之前我们写的程序的数据都是存储到内存里面的&#xff0c;当程序结束时&#xff0c;内存回收&#xff0c;数据丢失&#xff0c; 再次运行程序时&#xff0c;就看不到上次程序的数据&#xff0c;如果要程序的数据一直保存得使用文件 二.文件 文件一般可以…

华为OD机试真题——数据分类(2025B卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 B卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享》 华为OD机试真题《数据…

JavaWeb开发基础Servlet生命周期与工作原理

Servlet生命周期 Servlet的生命周期由Servlet容器(如Tomcat、Jetty等)管理&#xff0c;主要包括以下5个阶段&#xff1a; 加载Servlet类 创建Servlet实例 调用init方法 调用service方法 调用destroy方法 加载(Loading)&#xff1a; 当Servlet容器启动或第一次接收到对某个…

三防平板科普:有什么特殊功能?应用在什么场景?

在数字化浪潮席卷全球的今天&#xff0c;智能设备已成为现代工业、应急救援、户外作业等领域的核心工具。然而&#xff0c;常规平板电脑在极端环境下的脆弱性&#xff0c;如高温、粉尘、水浸或撞击&#xff0c;往往成为制约效率与安全的短板。三防平板&#xff08;防水、防尘、…

百度外链生态的优劣解构与优化策略深度研究

本文基于搜索引擎算法演进与外链建设实践&#xff0c;系统剖析百度外链的作用机制与价值模型。通过数据统计、案例分析及算法逆向工程&#xff0c;揭示不同类型外链在权重传递、流量获取、信任背书等维度的差异化表现&#xff0c;提出符合搜索引擎规则的外链建设技术方案&#…

【速写】PPOTrainer样例与错误思考(少量DAPO)

文章目录 序言1 TRL的PPO官方样例分析2 确实可行的PPOTrainer版本3 附录&#xff1a;DeepSeek关于PPOTrainer示例代码的对话记录Round 1&#xff08;给定模型数据集&#xff0c;让它开始写PPO示例&#xff09;Round 2 &#xff08;指出PPOTrainer的参数问题&#xff09;关键问题…

5.26 面经整理 360共有云 golang

select … for update 参考&#xff1a;https://www.cnblogs.com/goloving/p/13590955.html select for update是一种常用的加锁机制&#xff0c;它可以在查询数据的同时对所选的数据行进行锁定&#xff0c;避免其他事务对这些数据行进行修改。 比如涉及到金钱、库存等。一般这…

中国移动咪咕助力第五届全国人工智能大赛“AI+数智创新”专项赛道开展

第五届全国人工智能大赛由鹏城实验室主办&#xff0c;新一代人工智能产业技术创新战略联盟承办&#xff0c;华为、中国移动、鹏城实验室科教基金会等单位协办&#xff0c;广东省人工智能与机器人学会支持。 大赛发布“AI图像编码”、“AI增强视频质量评价”、“AI数智创新”三大…

模具制造业数字化转型:精密模塑,以数字之力铸就制造基石

模具被誉为 “工业之母”&#xff0c;是制造业的重要基石&#xff0c;其精度直接决定了工业产品的质量与性能。在工业制造向高精度、智能化发展的当下&#xff0c;《模具制造业数字化转型&#xff1a;精密模塑&#xff0c;以数字之力铸就制造基石》这一主题&#xff0c;精准点明…

PECVD 生成 SiO₂ 的反应方程式

在PECVD工艺中&#xff0c;沉积氧化硅薄膜以SiH₄基与TEOS基两种工艺路线为主。 IMD Oxide&#xff08;USG&#xff09; 这部分主要沉积未掺杂的SiO₂&#xff0c;也叫USG&#xff08;Undoped Silicate Glass&#xff09;&#xff0c;常用于IMD&#xff08;Inter-Metal Diele…

2024 CKA模拟系统制作 | Step-By-Step | 17、题目搭建-排查故障节点

目录 免费获取题库配套 CKA_v1.31_模拟系统 一、题目 二、考点分析 1. Kubernetes 节点状态诊断 2. 节点故障修复技能 3. 持久化修复方案 4. SSH 特权操作 三、考点详细讲解 1. 节点状态机制详解 2. 常见故障原因深度分析 3. 永久修复技术方案 四、实验环境搭建步骤…

如何将图像插入 PDF:最佳工具比较

无论您是编辑营销材料、写报告还是改写原来的PDF文件&#xff0c;将图像插入 PDF 都至关重要。幸运的是&#xff0c;有多种在线和离线工具可以简化此任务。在本文中&#xff0c;我们将比较一些常用的 PDF 添加图像工具&#xff0c;并根据您的使用场景推荐最佳解决方案&#xff…

人工智能与机器学习从理论、技术与实践的多维对比

人工智能(Artificial Intelligence, AI)提出“让机器像人类一样思考”的目标,其核心理论围绕符号系统假设展开——认为智能行为可通过逻辑符号系统(如谓词逻辑、产生式规则)建模。 机器学习(Machine Learning, ML)是人工智能的子集,聚焦于通过数据自动改进算法性能的理…

什么是 WPF 技术?什么是 WPF 样式?下载、安装、配置、基本语法简介教程

什么是 WPF 技术&#xff1f;什么是 WPF 样式&#xff1f;下载、安装、配置、基本语法简介教程 摘要 WPF教程、WPF开发、.NET 8 WPF、Visual Studio 2022 WPF、WPF下载、WPF安装、WPF配置、WPF样式、WPF样式详解、XAML语法、XAML基础、MVVM架构、数据绑定、依赖属性、资源字典…

流程自动化引擎:让业务自己奔跑

在当今竞争激烈的商业环境中&#xff0c;企业面临着快速变化的市场需求、日益复杂的业务流程以及不断增长的运营成本。如何优化业务流程、提升效率并降低成本&#xff0c;成为企业持续发展的关键问题。 流程自动化引擎&#xff08;Process Automation Engine&#xff09;作为一…

AI炼丹日志-23 - MCP 自动操作 自动进行联网检索 扩展MCP能力

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇&#xff1a; MyBatis 更新完毕目前开始更新 Spring&#xff0c;一起深入浅出&#xff01; 大数据篇 300&#xff1a; Hadoop&…

用 Python 模拟雪花飘落效果

用 Python 模拟雪花飘落效果 雪花轻轻飘落&#xff0c;给冬日带来一份浪漫与宁静。本文将带你用一份简单的 Python 脚本&#xff0c;手把手实现「雪花飘落效果」动画。文章深入浅出&#xff0c;零基础也能快速上手&#xff0c;完整代码仅需一个脚本文件即可运行。 目录 前言…