[LeetCode 周赛187] 4. 有序矩阵中的第 k 个最小数组和(暴力、优先队列、二分法、巧妙解法)

文章目录

    • 1. 题目来源
    • 2. 题目说明
    • 3. 题目解析
      • 方法一:暴力+巧妙解法
      • 方法二:优先队列+bfs+巧妙解法
      • 方法三:二分+dfs+巧妙解

1. 题目来源

链接:5403. 有序矩阵中的第 k 个最小数组和

2. 题目说明

[LeetCode 周赛187] 4. 有序矩阵中的第 k 个最小数组和(暴力、优先队列、二分法、巧妙解法)_第1张图片
[LeetCode 周赛187] 4. 有序矩阵中的第 k 个最小数组和(暴力、优先队列、二分法、巧妙解法)_第2张图片

3. 题目解析

方法一:暴力+巧妙解法

有一说一,题是好理解,但是真难做…最后 1 个多小时都在干这个题目,还是没能干出来…结果暴力就能过…真的…暴力出奇迹。

这个暴力不知道稳定不,在比赛时 cpp 貌似没过,java 可以,也都是听大佬讲的,自己想了一堆奇妙的方法,磕磕绊绊把自己绕进去了。

见题解大佬 Ikaruga【有序矩阵中的第 k 个最小数组和】抄作业。看了大佬的代码总是能学习几个新函数 。

二分 + dfs 应该是这道题很棒的解法了。

参见代码如下:

// 执行用时 :1376 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :156.1 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
public:
    int kthSmallest(vector<vector<int>>& mat, int k) {
        vector<int> ans(mat[0]);
        for (int i = 1; i < mat.size(); ++i) {
            multiset<int> st;
            for (int x : ans) {
                for (int y : mat[i]) {
                    st.insert(x + y);
                }
            }
            ans.assign(st.begin(), st.end());
            ans.resize(min(k, (int)ans.size()));
        }
        return ans.back();
    }
};


作者:newbie-19
链接:https://leetcode-cn.com/problems/find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows/solution/er-fen-by-newbie-19-3/
来源:力扣(LeetCode)
class Solution {
public:
    int kthSmallest(vector<vector<int>>& mat, int k) {
        int m=mat.size(),n=mat[0].size();
        multiset<int>s(mat[0].begin(),mat[0].end());
        for(int i=1;i<m;i++){
            multiset<int>temp;
            for(int x : s){
                for(int y : mat[i]){
                    temp.insert(x+y);
                }
            }
            s.clear();
            auto it=temp.begin();
            for(int j=0;j<min(k,(int)temp.size());j++,it++){
                s.insert(*it);
            }
        }
        return *s.rbegin();
    }
};

方法二:优先队列+bfs+巧妙解法

来自坑神的代码+思路…由于数据最大为 40 * 200 = 8000 故可选择暴力去做。坑神一开始想精细化的去 bfs 即在优先队列中仅保留 200 个理想状态即可,但是确实很麻烦就改道暴力了。

有一说一,代码没看太懂,bfs 学的菜…人被这个题整蒙了…

参考代码如下:

// 执行用时 :284 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :13 MB, 在所有 C++ 提交中击败了100.00%的用户

const int INF = 1e9;
int n, m;
vector<vector<int>> mat;
struct Node {
    int cur[41], sum = 0;
    
    Node(){
        sum = 0;
        for (int i = 0; i < n; i++)
            sum = sum + mat[i][cur[i] = 0];
    }
    
    Node getNext(int k){
        Node ret;
        for (int i = 0; i < n; i++) ret.cur[i] = cur[i];
        ret.cur[k]++; ret.sum = 0;
        for (int i = 0; i < n; i++) ret.sum += mat[i][ret.cur[i]];
        return ret;
    }
    
    string i2s(int x){
        string ret = "";
        while(x){
            ret += (char)(x % 10 + '0');
            x /= 10;
        }
        return ret;
    }
    
    string getString(){
        string ret = "";
        for (int i = 0; i < n; i++)
            ret += "#" + i2s(cur[i]);
        return ret;
    }
    
    friend bool operator < (const Node &a, const Node &b){
        return a.sum > b.sum;
    }
};

set<string> hash_que;
priority_queue<Node> que;

class Solution {
public:
    int kthSmallest(vector<vector<int>>& v, int k) {
        mat = v; n = mat.size(); m = mat[0].size();
        
        while(!que.empty()) que.pop();
        que.push(Node()); hash_que.clear();
        
        int cnt = 0;
        while(!que.empty()){
            Node x = que.top(); que.pop();
            if (hash_que.insert(x.getString()).second){
                ++cnt;
                if (cnt == k) return x.sum;
                for (int i = 0; i < n; i++)
                    if (x.cur[i] + 1 < m) que.push(x.getNext(i));
            }
        }
        
        return 0;
    }
};

方法三:二分+dfs+巧妙解

依旧见题解大佬 Ikaruga【有序矩阵中的第 k 个最小数组和】抄作业。

大佬解释原图:
[LeetCode 周赛187] 4. 有序矩阵中的第 k 个最小数组和(暴力、优先队列、二分法、巧妙解法)_第3张图片

newbie大佬二分高赞答案

[LeetCode 周赛187] 4. 有序矩阵中的第 k 个最小数组和(暴力、优先队列、二分法、巧妙解法)_第4张图片

class Solution {
public:
    int kthSmallest(vector<vector<int>>& mat, int k) {
        int l = 0;
        int r = 0;
        for (int i = 0; i < mat.size(); i++) {
            l += mat[i].front();
            r += mat[i].back();
        }

        int base = l;
        while (l < r) {
            int mid = l + (r - l) / 2;
            int cnt = 1;
            dfs(mat, k, mid, 0, base, cnt);
            if (cnt < k) {
                l = mid + 1;
            }
            else {
                r = mid;
            }
        }
        return r;
    }

    void dfs(vector<vector<int>>& mat, int k, int maxSum, int idx, int sum, int& cnt) {
        if (idx == mat.size()) return;
        if (sum > maxSum || cnt > k) return;

        dfs(mat, k, maxSum, idx + 1, sum, cnt);

        for (int j = 1; j < mat[idx].size(); j++) {
            int temp = sum + mat[idx][j] - mat[idx][0];
            if (temp > maxSum) break;
            cnt++;
            dfs(mat, k, maxSum, idx + 1, temp, cnt);
        }
    }
};


作者:newbie-19
链接:https://leetcode-cn.com/problems/find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows/solution/er-fen-by-newbie-19-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
    vector<vector<int>>temp;
    int m,n;
    int kthSmallest(vector<vector<int>>& mat, int k) {
        temp=mat;
        m=mat.size(),n=mat[0].size();
        int left=0,right=0;
        for(int i=0;i<m;i++) left+=mat[i][0],right+=mat[i].back();
        int init=left;
        while(left<right){
            int mid=(left+right)>>1;
            int num=1;
            dfs(mid,0,init,num,k);
            if(num>=k) right=mid;
            else left=mid+1;
        }
        return left;
    }
    void dfs(int mid,int index,int sum,int& num,int k){
        if(sum>mid||index==m||num>k) return;
        dfs(mid,index+1,sum,num,k);
        for(int i=1;i<n;i++){
            if(sum+temp[index][i]-temp[index][0]<=mid){
                num++;
                dfs(mid,index+1,sum+temp[index][i]-temp[index][0],num,k);
            }else{
                break;
            }
        }
    }
};

你可能感兴趣的:(LeetCode周赛)