当前位置:首页 > 牛客 > 牛客17799题:滑动窗口+优先队列解决多数组最小区间

牛客17799题:滑动窗口+优先队列解决多数组最小区间

1个月前 (08-06)

牛客17799题:滑动窗口+优先队列解决多数组最小区间 滑动窗口 牛客题解 优先队列 C++ 第1张

一、题目解读

牛客17799题要求在一个由K个有序数组组成的集合中,找到包含所有数组元素的最小区间范围。即需确定一个区间[range_start, range_end],使得每个数组中至少有一个元素落在该区间内,且区间长度最小。题目考验对多数组合并与区间优化的处理能力。

二、解题思路

采用“滑动窗口+优先队列”策略:

1. 初始化:将每个数组的首元素加入小根堆(优先队列),记录当前堆顶元素(最小值)与最大值。

2. 滑动窗口:每次取出堆顶元素(当前窗口最小值),更新区间范围。若该元素所在数组存在后续元素,则将其加入堆并更新最大值。

3. 循环终止条件:当某个数组的所有元素已被遍历时结束,确保每个数组至少贡献一个元素到区间。

4. 区间更新逻辑:通过比较新旧区间的长度和起始值,动态维护最小范围。

三、解题步骤

1. 创建包含元素值、行索引、列索引的结构体,重载运算符支持优先队列排序

2. 初始化堆:遍历K个数组首元素,加入堆并记录当前最大值。

3. 循环:

○ 弹出堆顶元素,更新区间范围(根据差值或起始值优先级)。

○ 若该元素非所在数组末尾,则将其下一元素加入堆并更新最大值。

○ 若某数组遍历完毕,终止循环。

4. 返回最终区间[range_start, range_end]。

四、代码与注释

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

struct Element {
    int val;    // 元素值
    int row;    // 所属数组索引
    int col;    // 在数组中的位置
    
    bool operator>(const Element& other) const {
        return val > other.val;
    }
};

vector<int> smallestRange(vector<vector<int>>& nums) {
    int k = nums.size();
    priority_queue<Element, vector<Element>, greater<Element>> min_heap;
    
    int current_max = INT_MIN;
    // 初始化堆,放入每个数组的第一个元素
    for (int i = 0; i < k; ++i) {
        min_heap.push({nums[i][0], i, 0});
        current_max = max(current_max, nums[i][0]);
    }
    
    int range_start = 0, range_end = INT_MAX;
    
    while (true) {
        Element min_element = min_heap.top();
        min_heap.pop();
        
        // 更新最小区间
        if (current_max - min_element.val < range_end - range_start) {
            range_start = min_element.val;
            range_end = current_max;
        } else if (current_max - min_element.val == range_end - range_start && 
                  min_element.val < range_start) {
            range_start = min_element.val;
            range_end = current_max;
        }
        
        // 如果某个数组已经遍历完,结束循环
        if (min_element.col + 1 == nums[min_element.row].size()) {
            break;
        }
        
        // 将当前数组的下一个元素加入堆
        int next_val = nums[min_element.row][min_element.col + 1];
        min_heap.push({next_val, min_element.row, min_element.col + 1});
        current_max = max(current_max, next_val);
    }
    
    return {range_start, range_end};
}

int main() {
    int k, n;
    cin >> k >> n;
    
    vector<vector<int>> nums(k, vector<int>(n));
    for (int i = 0; i < k; ++i) {
        for (int j = 0; j < n; ++j) {
            cin >> nums[i][j];
        }
    }
    
    vector<int> result = smallestRange(nums);
    cout << result[0] << " " << result[1] << endl;
    
    return 0;
}

五、总结

本解法核心在于利用优先队列维护多数组元素的有序性,通过滑动窗口动态调整区间范围,避免了暴力遍历所有组合。时间复杂度为O(NlogK)(N为总元素数,K为数组数量),空间复杂度为O(K)。通过优化区间更新逻辑,确保在相等长度时优先选择更小区间,从而准确求解最小范围。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣451:ASCII数组计数法 用128个桶解决频率排序问题

力扣451:ASCII数组计数法 用128个桶解决频率排序问题

题目重解给定一个字符串,将字符按照出现频率降序排列。例如输入"tree",可能返回"eetr"或"eert"。题目要求我们不考虑字母顺序,只...

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

题目解读‌我们面对的是一个典型的图论问题:给定一个城市的连接矩阵,需要计算其中相互连通的城市群(省份)数量。这个问题可以抽象为无向图中的连通分量计算,每个城市代表图中的一个节点,城市之间的连接关系代表...

力扣5:中心扩散法 轻松破解最长回文子串

力扣5:中心扩散法 轻松破解最长回文子串

题目解读:在一个给定的字符串中,我们需要找到最长的回文子串。回文是指正读反读都相同的字符串,如"aba"、"abba"都是回文。这个问题看似简单,但要在字符串中...

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

题目重解想象你是一名药师,有t分钟在山上采集m种草药。每种草药需要time分钟采集,价值为num。这就像考试时分配时间做题,要选择收益最大的题目组合。题目要求计算在规定时间内能获得的最大草药价值。解题...

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

题目重解给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们的目标是找到一条路径,使得路径上经过的数字总和最大。这个问题在实际中有许多应用场景,如最优路径规划、...

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

发表评论

访客

看不清,换一张

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