有序矩阵中的第 k 个最小数组和

给你一个 m * n 的矩阵 mat,以及一个整数 k ,矩阵中的每一行都以非递减的顺序排列
你可以从每一行中选出1个元素形成一个数组,返回所有可能数组中的第k个最小数组和

1. 暴力

逐行遍历
贪心记录加上当前行的值后,前k个最小数组和

class Solution {
public:
    int kthSmallest(vector<vector<int>> &mat, int k) {
        vector<int> pre = {0};//便于统一操作,初始为0
        for (auto &row: mat) {//遍历每一行
            vector<int> cur;//记录所有数组和
            for (int x: pre) //将之前的数组和
                for (int y: row)//加上当前行的值
                    cur.push_back(x + y);
            sort(cur.begin(), cur.end());//排序
            if (cur.size() > k) // 保留最小的 k 个
                cur.resize(k);
            pre = cur;
        }
        return pre.back();
    }
};

2. 小根堆(算法一优化)

利用小根堆优化了二维组合的贪心寻找
而不需要全部暴力列举再排序

class Solution {
    vector<int> kSmallestPairs(vector<int> &nums1, vector<int> &nums2, int k) {
        vector<int> ans;
        priority_queue<tuple<int, int, int>> pq;
        int n = nums1.size(), m = nums2.size();
        pq.emplace(-nums1[0] - nums2[0], 0, 0); // 取相反数变成小顶堆
        while (!pq.empty() && ans.size() < k) {//利用小根堆只存k个数,不用去暴力再排序,相当于广度优先搜索,但先搜索小的
            auto [_, i, j] = pq.top(); pq.pop();//两个数组对应下标
            ans.push_back(nums1[i] + nums2[j]); // 数对和,放入结果,该结果最小
            //关键语句,贪心思想,实际上类似在横向单调增,竖向单调增的二维数组上贪心移动指针
            if (j == 0 && i + 1 < n) //pre处于第一个数时
                pq.emplace(-nums1[i + 1] - nums2[0], i + 1, 0);//移动row 的 i下标,竖向扩张(不会横向拓展后再竖向,因为每行第一个元素一定更小)
            if (j + 1 < m)//无条件移动
                pq.emplace(-nums1[i] - nums2[j + 1], i, j + 1);//移动pre 的 j下标,横向扩张
        }
        return ans;
    }

public:
    int kthSmallest(vector<vector<int>> &mat, int k) {
        vector<int> pre = {0};
        for (auto &row: mat)
            pre = kSmallestPairs(row, pre, k);
        return pre.back();
    }
};

这样写扩张方式也可以
实际上利用组合递增的性质,就是限制一端的搜索,从而减少时间复杂度
当然也可以事先将一端全部入堆,然后再横向(纵向)扩展即可

if (i + 1 < n)//无条件移动
    pq.emplace(-nums1[i + 1] - nums2[j], i + 1, j);//移动row 的 i下标
if (i == 0 &&j + 1 < m)
    pq.emplace(-nums1[0] - nums2[j + 1], 0, j + 1);//移动pre 的 j下标
posted @ 2023-05-28 15:09  失控D大白兔  阅读(15)  评论(0编辑  收藏  举报