[LeetCode 周賽187] 4. 有序矩陣中的第 k 個最小數組和(暴力、優先隊列、二分法、巧妙解法)

1. 題目來源

鏈接:5403. 有序矩陣中的第 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 個最小數組和】抄作業

大佬解釋原圖:
在這裏插入圖片描述

newbie大佬二分高贊答案

在這裏插入圖片描述

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;
            }
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章