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

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

2个月前 (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)。通过优化区间更新逻辑,确保在相等长度时优先选择更小区间,从而准确求解最小范围。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣654:递归分治的艺术 如何用最大元素构建二叉树

力扣654:递归分治的艺术 如何用最大元素构建二叉树

题目重解我们面对一个看似简单却充满递归魅力的题目:给定一个不含重复元素的整数数组,需要构建一棵特殊的二叉树。这个树的每个父节点都必须是当前子数组中的最大元素,而它的左右子树则分别由该最大值左侧和右侧的...

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

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

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

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

一、题目解读洛谷1220题要求计算在n个位置放置灯的情况下,通过关闭连续区间灯并移动至区间端点,使得总耗电量最小。需考虑灯的功率与位置差异,设计高效的算法求解最优策略。二、解题思路1. 动态规划 +...

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

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

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

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

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

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

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

一、题目解读洛谷P1121题要求求解环形数组的最大子段和,即在一个环形数组中找到一个连续子段,使其元素和最大。环形数组的特殊性在于首尾元素可相连,需考虑线性子段与跨越首尾的环形子段两种情况。二、解题思...

发表评论

访客

看不清,换一张

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