当前位置:首页 > 洛谷 > 洛谷P1323题解:优先队列与单调栈解决删数问题

洛谷P1323题解:优先队列与单调栈解决删数问题

7个月前 (08-06)

洛谷P1323题解:优先队列与单调栈解决删数问题 洛谷题解 优先队列 最小堆 单调栈 贪心算法 第1张

一、题目解读

洛谷P1323题要求生成前k个最小的元素,并通过删除m个数字使剩余序列单调递增。题目需结合生成算法与优化删除策略,考验对数据结构与贪心思想的运用。

二、解题思路

1. 生成最小k数:利用优先队列最小堆)维护当前最小元素。每次取出队首元素,生成其衍生元素(2x+1和4x+5),避免重复后加入队列,直至得到k个元素。

2. 删除m数优化:将生成的数字拼接为字符串,采用单调栈策略。遍历字符时,若末尾数字小于当前数字且可删除次数剩余,则弹出栈顶直至满足条件,最终保留单调递增子序列

三、解题步骤

1. 输入k和m,初始化优先队列pq(最小堆)并加入初始元素1。

2. 循环k次:

    取出队首元素,若与上一元素重复则跳过。

    加入队列的新元素为2x+1和4x+5,确保队列始终维护最小元素。

3. 将生成的k个元素拼接为字符串numStr。

4. 遍历numStr,利用单调栈删除:

    若当前字符大于栈顶且可删除次数>0,弹出栈顶直至不满足条件。

    将当前字符入栈,最终栈中序列即为删除m个数字后的最大单调递增子串。

5. 若剩余删除次数未用完,从末尾截断字符串。

6. 输出原始序列和优化后的结果。

四、代码与注释

#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

int main() {
    int k, m;
    cin >> k >> m; // 输入k和m
    
    // 优先队列(最小堆)生成k个最小元素
    priority_queue<int, vector<int>, greater<int>> pq;
    vector<int> elements;
    pq.push(1); // 初始元素1
    
    while(elements.size() < k) {
        int current = pq.top(); // 取出最小元素
        pq.pop();
        // 避免重复元素
        if (!elements.empty() && current == elements.back()) {
            continue;
        }
        elements.push_back(current); // 加入有效元素
        // 生成新元素加入队列
        pq.push(2 * current + 1);
        pq.push(4 * current + 5);
    }
    
    // 拼接数字为字符串
    string numStr;
    for (int num : elements) {
        numStr += to_string(num);
    }
    cout << numStr << endl; // 输出原始序列
    
    // 单调栈删除m个数字优化
    string result;
    int remove = m;
    for (char digit : numStr) {
        // 贪心删除:若当前数字比栈顶大且可删除
        while (remove > 0 &&!result.empty() && digit > result.back()) {
            result.pop_back(); // 弹出栈顶
            remove--;
        }
        result.push_back(digit); // 加入当前数字
    }
    // 剩余删除次数从末尾截断
    if (remove > 0) {
        result = result.substr(0, result.size() - remove);
    }
    cout << result << endl; // 输出优化结果
    return 0;
}

五、总结

该解法巧妙结合优先队列与单调栈:前者高效生成有序序列,后者通过贪心策略删除元素确保单调性。代码简洁且逻辑清晰,避免复杂循环,时间复杂度低。解题时需注意重复元素的判断与删除操作的边界处理,是处理此类生成+优化问题的典型范例。

原创内容 转载请注明出处

分享给朋友:

相关文章

力扣1700题:无法吃午餐的学生数量 - 队列模拟解法详解

力扣1700题:无法吃午餐的学生数量 - 队列模拟解法详解

内容简介本文详细解析了力扣1700题"无法吃午餐的学生数量"的队列模拟解法。通过模拟学生排队取餐的过程,统计无法吃到喜欢三明治的学生数量。文章包含完整注释代码、算法思路讲解和复杂度...

牛客13271题「删除K个数字的最小数」解题报告:贪心算法与栈的应用(附代码注释)

牛客13271题「删除K个数字的最小数」解题报告:贪心算法与栈的应用(附代码注释)

一、题目解读牛客13271题要求从给定的数字字符串中删除K个数字,使得剩余数字按原顺序排列后得到的最小数。题目核心在于如何在保持数字相对顺序的前提下,通过删除操作得到最优解。需注意结果字符串可能包含前...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

一、题目解读洛谷1656题要求在无向图中找出所有割边(即删除后导致图不连通的边)。题目核心在于判断图的连通性,并识别哪些边是“桥”。需理解图论中的连通分量概念,以及如何通过算法高效定位割边。二、解题思...

洛谷P1168题:中位数 解题思路全解析,C++实现

洛谷P1168题:中位数 解题思路全解析,C++实现

一、题目解读洛谷P1168题要求处理一个动态数据流,实时输出前奇数项的中位数。中位数定义为有序数列中间位置的元素,需解决数据插入与统计的实时性。题目核心在于设计高效数据结构,快速定位中位数并应对数据变...

洛谷2652题解析:同花顺排序问题的动态规划与滑动窗口优化

洛谷2652题解析:同花顺排序问题的动态规划与滑动窗口优化

一、题目解读洛谷2652题要求对一组扑克牌进行排序,目标是找到最少需要调整的次数,使得所有牌形成同花顺。题目中,扑克牌由花色和数字组成,需先按花色排序,再在同花色内按数字排序。核心难点在于如何处理花色...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。