C++二分查找算法:有序矩陣中的第 k 個最小數組和

本文涉及的基礎知識點

二分查找算法合集

本題的簡化

C++二分查找算法:查找和最小的 K 對數字 十分接近m恒等于2

題目

給你一個 m * n 的矩陣 mat,以及一個整數 k ,矩陣中的每一行都以非遞減的順序排列。
你可以從每一行中選出 1 個元素形成一個數組。返回所有可能數組中的第 k 個 最小 數組和。
示例 1:
輸入:mat = [[1,3,11],[2,4,6]], k = 5
輸出:7
解釋:從每一行中選出一個元素,前 k 個和最小的數組分別是:
[1,2], [1,4], [3,2], [3,4], [1,6]。其中第 5 個的和是 7 。
示例 2:
輸入:mat = [[1,3,11],[2,4,6]], k = 9
輸出:17
示例 3:
輸入:mat = [[1,10,10],[1,4,5],[2,3,6]], k = 7
輸出:9
解釋:從每一行中選出一個元素,前 k 個和最小的數組分別是:
[1,1,2], [1,1,3], [1,4,2], [1,4,3], [1,1,6], [1,5,2], [1,5,3]。其中第 7 個的和是 9 。
示例 4:
輸入:mat = [[1,1,10],[2,2,9]], k = 7
輸出:12
參數范圍
m == mat.length
n == mat.length[i]
1 <= m, n <= 40
1 <= k <= min(200, n ^ m)
1 <= mat[i][j] <= 5000
mat[i] 是一個非遞減數組

分析

時間復雜度

O(mlog(500040)n+mkn)。GetLessKSum被調用m次,GetLessEqualSumNum共被調用mlog(500040)次。每次調用GetLessEqualSumNum,for循環共執行m次。
vRet.emplace_back極端情況下,可能被執行k
n次。

主要函數介紹

GetLessKSum兩行升序數據的最小k個和
GetLessEqualSumNum兩行升序數據和小于等于iSum的組合數量

注意:nums[i]為正數,所以如果pre的數量大于k,只需要保留前k小,其它的被淘汰了。

二分

尋找第一個符合條件的iSum,條件如下:
和小于等于iSum的組合數量大于等于k。

代碼

核心代碼

class Solution {
public:int kthSmallest(vector<vector<int>>& mat, int k) {m_c = mat.front().size();m_iK = k;vector<int> pre = mat[0];for (int r = 1; r < mat.size(); r++){pre = GetLessKSum(pre, mat[r]);}return pre.back();}vector<int> GetLessKSum(const vector<int>& pre, const vector<int>& cur){int left = 0, right = 5000 * 40;while (right - left > 1){const auto mid = left + (right - left) / 2;if (GetLessEqualSumNum(pre, cur, mid)>= m_iK){right = mid;}else{left = mid;}}vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu <= right){vRet.emplace_back(pr + cu);}else{break;}}}sort(vRet.begin(), vRet.end());if (vRet.size() > m_iK){vRet.erase(vRet.begin() + m_iK, vRet.end());}return vRet;}int GetLessEqualSumNum(const vector<int>& pre, const vector<int>& cur,int iSum){int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr)- cur.begin();}return iNum;}int m_iK;int m_c;
};

測試用例

template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
Assert(v1[i], v2[i]);
}
}

int main()
{
vector<vector> mat;
int k;
int res;
{
Solution slu;
mat = { {1,3,11},{2,4,6} };
k = 5;
res = slu.kthSmallest(mat, k);
Assert(7, res);
}
{
Solution slu;
mat = { {1,3,11},{2,4,6} };
k = 9;
res = slu.kthSmallest(mat, k);
Assert(17, res);
}
{
Solution slu;
mat = { {1,10,10},{1,4,5},{2,3,6} };
k = 7;
res = slu.kthSmallest(mat, k);
Assert(9, res);
}
{
Solution slu;
mat = { {1,1,10},{2,2,9} };
k = 7;
res = slu.kthSmallest(mat, k);
Assert(12, res);
}

//CConsole::Out(res);

}

優化增加結果

vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu < right){vRet.emplace_back(pr + cu);}else{break;}}}while (vRet.size() < m_iK){vRet.emplace_back(right);}

和小于right的數量<=k,如果不足夠,則補right。時間復雜度由O(nk)降低到O(k+n)。

直接使用封裝類

namespace NBinarySearch
{template<class INDEX_TYPE,class _Pr>INDEX_TYPE FindFrist(INDEX_TYPE left, INDEX_TYPE right, _Pr pr){while (right - left > 1){const auto mid = left + (right - left) / 2;if (pr(mid)){right = mid;}else{left = mid;}}return right;}
}class Solution {
public:int kthSmallest(vector<vector<int>>& mat, int k) {m_c = mat.front().size();m_iK = k;vector<int> pre = mat[0];for (int r = 1; r < mat.size(); r++){pre = GetLessKSum(pre, mat[r]);}return pre.back();}vector<int> GetLessKSum(const vector<int>& pre, const vector<int>& cur){auto GetLessEqualSumNum = [&pre, &cur, this](const int iSum)-> bool{int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr) - cur.begin();}return iNum >= m_iK;};const int right = NBinarySearch::FindFrist(0, 5000 * 40, GetLessEqualSumNum);		vector<int> vRet;for (const auto& pr : pre){for (const auto& cu : cur){if (pr + cu < right){vRet.emplace_back(pr + cu);}else{break;}}}while (vRet.size() < m_iK){vRet.emplace_back(right);}sort(vRet.begin(), vRet.end());if (vRet.size() > m_iK){vRet.erase(vRet.begin() + m_iK, vRet.end());}return vRet;}int GetLessEqualSumNum(const vector<int>& pre, const vector<int>& cur,int iSum){int iNum = 0;for (const auto& pr : pre){iNum += std::upper_bound(cur.begin(), cur.end(), iSum - pr)- cur.begin();}return iNum;}int m_iK;int m_c;
};

2023年3月暴力版

直接保留前k個。時間復雜度:O(mknlogk)
class Solution {
public:
int kthSmallest(vector<vector>& mat, int k) {
m_r = mat.size();
m_c = mat[0].size();
std::priority_queue pre;
pre.push(0);
for (int r = 0; r < mat.size(); r++)
{
std::priority_queue dp;
while (pre.size())
{
int t = pre.top();
pre.pop();
for (int c = 0; c < m_c; c++)
{
dp.push(mat[r][c] + t);
if (dp.size() > k)
{
dp.pop();
}
}
}
pre.swap(dp);
}
return pre.top();
}
int m_r, m_c;
};

擴展閱讀

視頻課程

有效學習:明確的目標 及時的反饋 拉伸區(難度合適),可以先學簡單的課程,請移步CSDN學院,聽白銀講師(也就是鄙人)的講解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成戰斗了,為老板分憂,請學習C#入職培訓、C++入職培訓等課程
https://edu.csdn.net/lecturer/6176

相關下載

想高屋建瓴的學習算法,請下載《喜缺全書算法冊》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想對大家說的話
聞缺陷則喜是一個美好的愿望,早發現問題,早修改問題,給老板節約錢。
墨子曰:事無終始,無務多業。也就是我們常說的專業的人做專業的事。
如果程序是一條龍,那算法就是他的是睛

測試環境

操作系統:win7 開發環境: VS2019 C++17
或者 操作系統:win10 開發環境:

VS2022 C++17

本文涉及的基礎知識點

C++算法:前綴和、前綴乘積、前綴異或的原理、源碼及測試用例 包括課程視頻

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164808.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164808.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164808.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

哈希unordered_set,unordered_map的練習

349. 兩個數組的交集 給定兩個數組 nums1 和 nums2 &#xff0c;返回 它們的交集 。輸出結果中的每個元素一定是 唯一 的。我們可以 不考慮輸出結果的順序 。 示例 1&#xff1a; 輸入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 輸出&#xff1a;[2]示例 2&#xff1a; 輸…

JSP過濾器和監聽器

什么是過濾器 Servlet過濾器與Servlet十分相似&#xff0c;但它具有攔截客戶端&#xff08;瀏覽器&#xff09;請求的功能&#xff0c;Servlet過濾器可以改變請求中的內容&#xff0c;來滿足實際開發中的需要。 對于程序開發人員而言&#xff0c;過濾器實質就是在Web應用服務器…

使用Wireshark提取流量中圖片方法

0.前言 記得一次CTF當中有一題是給了一個pcapng格式的流量包&#xff0c;flag好像在某個響應中的圖片里。比較簡單&#xff0c;后來也遇到過類似的情況&#xff0c;所以總結和記錄一下使用Wireshark提取圖片的方法。 提取的前提是HTTP協議&#xff0c;至于HTTPS的協議需要導入服…

【算法】摩爾投票算法

目錄 1.概述2.算法思想3.代碼實現3.1.t ?n / 2?3.2.t ?n / 3?3.3.t ?n / (m 1)? 4.應用 參考&#xff1a;LeetCode_多數元素 II 題解 1.概述 &#xff08;1&#xff09;摩爾投票法 (Boyer–Moore Majority Vote Algorithm) 是一種用來尋找一組元素中多數元素的常量級…

flutter,uni-app開發調試ios

一、申請ios開發者賬號 二、ios開發者配置 ios 開發者需要配置的地方 https://developer.apple.com/account/resources/certificates/list Certificates&#xff08;證書&#xff09;: 作用&#xff1a; 證書用于對應用程序和開發者進行身份驗證&#xff0c;確保安全性和可…

如何為您的企業選擇合適的多因素認證?

在傳統的網絡安全架構中&#xff0c;重點在于防止非法入侵&#xff0c;例如防火墻、VPN 、堡壘機等安全設備的重心都在于防止用戶違規訪問企業資源&#xff0c;一旦合法用戶的賬號密碼被入侵者拿到&#xff0c;就可以冒充合法用戶訪問企業資源&#xff0c;所有的安全設備形同虛…

springcloud超市管理系統源碼

技術說明&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui mysql 功能介紹&#xff1a; 后臺管理&#xff1a; 統計分析&#xff1a;查看用戶&#xff0c;商品&#xff0c;銷售數量&#xff1b;…

Mock 數據

1. Mock 數據的方式 2. json-server 實現 Mock 數據 項目中安裝json-server npm i -D json-server準備一個json文件添加啟動命令 //package.json"scripts": {"start": "craco start","build": "craco build","test&q…

簡單聊聊加密和加簽的關系與區別

大家好&#xff0c;我是G探險者。 平時我們在項目上一定都聽過加密和加簽&#xff0c;加密可能都好理解&#xff0c;知道它是保障的數據的機密性&#xff0c;那加簽是為了保障啥勒&#xff1f;它和加密有啥區別&#xff1f; 帶著這個疑問&#xff0c;我們就來聊聊二者的區別。…

SHEIN出口車鑰匙扣REACH認證指南解析

鑰匙扣的材料一般為金屬、皮革、塑料、橡膠、木頭等。此物精致小巧、造型千變萬化是人們隨身攜帶的日常用品。鑰匙扣是掛在鑰匙圈上的一種裝飾物品。鑰匙扣出口需要辦理REACH認證。 一、什么是REACH認證&#xff1f; REACH認證是歐盟28個成員國對進入其市場的所有化學品,&…

centos7中通過minikube安裝Kubernetes

minikube是一款開源的Kubernetes集群管理器&#xff0c;它可以幫助您在本地計算機上輕松部署和管理Kubernetes集群。以下是minikube的安裝和使用步驟&#xff1a; 安裝Docker&#xff1a;如果您還沒有安裝Docker&#xff0c;可以從Docker官方網站上下載并安裝適合您操作系統的…

Android和iOS應用程序加固方法詳解:混淆、加殼、數據加密、動態加載和數字簽名實現

目錄 Android和iOS應用程序加固方法詳解&#xff1a;混淆、加殼、數據加密、動態加載和數字簽名實現 APP 加固方式 iOS APP加固代碼實現 打開要處理的IPA文件 設置簽名使用的證書和描述文件 開始ios ipa重簽名 APP 加固方式 iOSAPP 加固是優化 iOS安全性的一種方法&…

C#枚舉的使用

在C#中經常會用到枚舉&#xff0c;是比較常用的定義一組常量集合的數據類型。我們使用枚舉可以更方便理解和閱讀代碼&#xff0c;增強代碼可讀性&#xff0c;也在某種程度上提升了編程邏輯和維度。 基本語法&#xff1a; enum MyEnum {Value1,Value2,Value3&#xff0c;//...…

CSS 實現文本框簽名

<div class"textarea-prepend"><textarea rows"6" placeholder"請輸入消息內容"></textarea></div>.textarea-prepend {position: relative;}.textarea-prepend textarea {width: 300px;}.textarea-prepend::before {ba…

UE4基礎篇十三:物理

一、筆記記錄 1.1 碰撞交互 阻擋會設置為阻擋的兩個(或更多)Actor之間自然發生。但是,需要啟用模擬生成命中事件(Simulation Generates Hit Events)才能執行事件命中 ,要兩個都相互設置阻擋模式才會生成命中事件 將Actor設置為重疊往往看起來它們彼此忽略,如果沒有生…

【陳老板贈書活動 - 18期】-如何成為架構師這幾本書推薦給你

陳老老老板&#x1f9b8; &#x1f468;?&#x1f4bb;本文專欄&#xff1a;贈書活動專欄&#xff08;為大家爭取的福利&#xff0c;免費送書&#xff09; &#x1f468;?&#x1f4bb;本文簡述&#xff1a;生活就像海洋,只有意志堅強的人,才能到達彼岸。 &#x1f468;?&am…

JavaScript基礎—引入方式、注釋和結束符、輸入和輸出、變量、常量、數據類型、檢測數據類型、類型轉換、綜合案例—用戶訂單信息

版本說明 當前版本號[20231123]。 版本修改說明20231123初版 目錄 文章目錄 版本說明目錄JavaScript 基礎 - 第1天介紹引入方式內部方式外部形式 注釋和結束符單行注釋多行注釋 結束符輸入和輸出輸出輸入 變量聲明賦值變量初始化更新變量 關鍵字變量名命名規則 常量數據類型…

什么是指針碰撞

程序員的公眾號&#xff1a;源1024&#xff0c;獲取更多資料&#xff0c;無加密無套路&#xff01; 最近整理了一波電子書籍資料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虛擬機》&#xff0c;《重構改善既有代碼設計》&#xff0c;《MySQL高性能-第3版》&…

WorkPlus實現完全私有化部署,企業數據安全有保障

在這個信息化飛速發展的時代&#xff0c;企業正面臨著越來越多的數據安全挑戰。為了確保數據的安全性和隱私性&#xff0c;WorkPlus迎合市場需求&#xff0c;推出了完全私有化部署方案&#xff0c;為企業提供了全面、可靠的安全保障&#xff0c;成為企業移動辦公的首選。 WorkP…

C#中的迭代器和分部類

目錄 一、迭代器 1.示例源碼 2.生成效果&#xff1a; 二、分部類 1.示例源碼 2.生成效果 迭代器在集合類中經常使用&#xff0c;而分部類則提供了一種將一個類分成多個類的方法&#xff0c;這對于有大量代碼的類非常實用。 一、迭代器 迭代器是可以返回相同類型的值的有…