Leetcode 刷題記錄 06 —— 矩陣

本系列為筆者的?Leetcode 刷題記錄,順序為 Hot 100 題官方順序,根據標簽命名,記錄筆者總結的做題思路,附部分代碼解釋和疑問解答。

目錄

01 矩陣置零

方法一:標記數組

方法二:兩個標記變量

02 螺旋矩陣

方法一:模擬

方法二:按層模擬

03 旋轉圖像

方法一:輔助數組

方法二:原地旋轉

方法三:用翻轉代替旋轉

04 搜索二維矩陣 Ⅱ

方法一:直接查找

方法二:二分法

方法三:Z字形查找


01 矩陣置零

class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {}
};
方法一:標記數組

時間復雜度 O(mn),空間復雜度 O(m + n)

  • 建立兩個數組 row(m)col(n),存儲 matrix 中行和列的含零情況

  • 遍歷數組,判斷行或列含零,執行 matrix[i][j] = 0

class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {int m = matrix.size();int n = matrix[0].size();vector<int> row(m), col(n);for(int i=0; i<m; ++i){for(int j=0; j<n; ++j){if(!matrix[i][j]){row[i] = true;col[j] = true;}}}for(int i=0; i<m; ++i){for(int j=0; j<n; ++j){if(row[i] || col[j]){matrix[i][j] = 0;}}}}
};

vector<int> row(m), col(n);這倆數組沒有初始化啥的嗎,它們聲明時的默認元素值是多少?

使用?vector<int> row(m)?這樣的語句聲明一個?vector并指定大小時,?vector會自動初始化為指定大小的元素,且每個元素默認初始化為零。

方法二:兩個標記變量

時間復雜度 O(mn),空間復雜度 O(1)

  • 建立兩個標記 flag_col0flag_row0,存儲 matrix 中除第零行和第零列的含零情況

  • 遍歷數組,判斷 !matrix[i][0] || !matrix[0][j],執行 matrix[i][j] = 0

  • 第零行和第零列單獨更新

class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {int m = matrix.size(); //一共m行int n = matrix[0].size(); //一共n列int flag_col0 = false, flag_row0 = false;for(int i=0; i<m; ++i){if(!matrix[i][0]) flag_col0 = true;}for(int j=0; j<n; ++j){if(!matrix[0][j]) flag_row0 = true;}//處理大部分元素for(int i=1; i<m; ++i){for(int j=1; j<n; ++j){if(!matrix[i][j]){matrix[i][0] = 0;matrix[0][j] = 0;}}}for(int i=1; i<m; ++i){for(int j=1; j<n; ++j){if(!matrix[i][0] || !matrix[0][j]) {matrix[i][j] = 0;}}}//處理第零行、第零列元素if(flag_col0){for(int i=0; i<m; ++i){matrix[i][0] = 0;}}if(flag_row0){for(int j=0; j<n; ++j){matrix[0][j] = 0;}}}
};

02 螺旋矩陣

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {}
};
方法一:模擬

時間復雜度 O(mn),空間復雜度 O(mn)

  • 建立二維數組 visited(rows, vector<bool>(columns),存儲矩陣元素的訪問情況

  • 遍歷矩陣,判斷 nextRownextColumn 是否越過邊界

class Solution {
public:static constexpr int dirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; //向右、下、左、上vector<int> spiralOrder(vector<vector<int>>& matrix) {if (matrix.size() == 0 || matrix[0].size() == 0) return {};int rows = matrix.size(), columns = matrix[0].size(), total = rows * columns;vector<vector<bool>> visited(rows, vector<bool>(columns)); //標記vector<int> order(total); //答案int row = 0, column = 0, dirIndex = 0;for(int i=0; i<total; i++){order[i] = matrix[row][column]; //更新答案visited[row][column] = true; //更新標記int nextRow = row + dirs[dirIndex][0];int nextColumn = column + dirs[dirIndex][1];if(nextRow >= rows || nextRow < 0 || nextColumn >= columns || nextColumn < 0 || visited[nextRow][nextColumn]){dirIndex = (dirIndex + 1) % 4;}row += dirs[dirIndex][0];column += dirs[dirIndex][1];}return order;}
};

static 意味著變量在程序的生命周期內只會被分配一次,并且在所有對該數組的函數調用中共享同一存儲空間。

constexpr 用于指定變量值在編譯時就確定下來,它提示編譯器盡量進行優化。

{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}每一對元素代表在二維平面上一個方向的坐標變換:

  • {0, 1}:代表向右移動 —— 行不變,列加一

  • {1, 0}:代表向下移動 —— 行加一,列不變

  • {0, -1}:代表向左移動 —— 行不變,列減一

  • {-1, 0}:代表向上移動 —— 行減一,列不變

vector<bool>(columns) 創建一個布爾向量,大小為 columns,其中每個元素默認初始化為 false

vector<vector<bool>>(rows, ...) 表示創建一個這樣的布爾向量的向量,其長度為 rows,即每一行都是一個布爾向量,且每列都是初始化為 false

spiral 螺旋形的 constexpr 常量表達式

⑦ 在什么樣的情況下 if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) 中的 nextRow < 0 成立?

由于初始位置是 (0, 0) 且遍歷順序是順時針螺旋,因此 nextRow < 0 通常在當前方向反轉嘗試向上之前使用過的路徑上被訪問時發生。

⑧ 將代碼中涉及 nextRownextColumn 部分的片段改為如下片段如何?

if((column == (columns - 1)) || (row == (rows - 1)) || (column == 0) || matrix[row + dirs[dirIndex][0]][column + dirs[dirIndex][1]]){dirIndex = (dirIndex + 1) % 4;
}

?matrix[row + dirs[dirIndex][0]][column + dirs[dirIndex][1]]:這種方式不僅增加了代碼復雜度,并且可能由于超出 matrix 的邊界而導致訪問無效內存,出現內存錯誤。

if (column == columns || row == rows || column == -1 || row == -1 ||
row + dirs[dirIndex][0] < 0 || row + dirs[dirIndex][0] >= rows ||
column + dirs[dirIndex][1] < 0 || column + dirs[dirIndex][1] >= columns || 
visited[row + dirs[dirIndex][0]][column + dirs[dirIndex][1]]) {
dirIndex = (dirIndex + 1) % 4;
}

row + dirs[dirIndex][0] < 0:檢查向當前方向移動后,新的行索引是否小于0。這會保持我們不越過上邊界。

row + dirs[dirIndex][0] >= rows:檢查向當前方向移動后,新的行索引是否大于或等于總行數。這會確保我們不越過下邊界。

column + dirs[dirIndex][1] < 0:檢查向當前方向移動后,新的列索引是否小于0。這會確保我們不越過左邊界。

column + dirs[dirIndex][1] >= columns:檢查向當前方向移動后,新的列索引是否大于或等于總列數。這會確保我們不越過右邊界。

方法二:按層模擬

時間復雜度 O(mn),空間復雜度 O(1)

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if(matrix.size() == 0 || matrix[0].size() == 0) return {};vector<int> order;int rows = matrix.size(), columns = matrix[0].size();int left = 0, right = columns-1, top = 0, bottom = rows-1;//主打一個遍歷while(left<=right && top<=bottom){for(int column=left; column<=right; ++column) {order.push_back(matrix[top][column]);}for(int row=top+1; row<=bottom; ++row) {order.push_back(matrix[row][right]);}if(left<right && top<bottom){for(int column=right-1; column>=left+1; --column) {order.push_back(matrix[bottom][column]);}for(int row=bottom; row>=top+1; --row) {order.push_back(matrix[row][left]);}}top++;left++;right--;bottom--;}return order;}
};

① 為什么還要第二次判斷 if(left<right && top<bottom) 呢?

在只有一行或者一列剩下時,第二次順時針迭代會導致重復元素被添加到結果中。例如,當只剩下一行時,上面的第二次和第三次迭代(從右向左)會和已經處理的行產生重復。比如:

  • 單行(例如,[[1, 2, 3]]

  • 單列(例如,[[1], [2], [3]]

03 旋轉圖像

class Solution {
public:void rotate(vector<vector<int>>& matrix) {}
};
方法一:輔助數組

時間復雜度 O(n^2),空間復雜度 O(n^2)

class Solution {
public:void rotate(vector<vector<int>>& matrix) {auto matrix_new = matrix;int n = matrix.size();for(int i=0; i<n; ++i){for(int j=0, j<n; ++j){matrix_new[j][n-1-i] = matrix[i][j];}}return matrix_new;}
};

auto matrix_new = matrix;這行代碼的作用是復制matrix變量的值到一個新的變量matrix_new中,matrix_new的類型與matrix一致。

對于大多數與標準庫相關的容器(如 std::vector),這會創建 matrix 的一個淺拷貝,整體上是深拷貝其內容,而不是僅僅復制指針(如果它是一個復雜數據結構)。

方法二:原地旋轉

時間復雜度 O(n^2),空間復雜度 O(1)

class Solution {
public:void rotate(vector<vector<int>>& matrix) {int n = matrix.size();for(int x=0; x<n/2; ++x){for(int y=0; y<(n+1)/2; ++y){int flag = matrix[x][y];matrix[x][y] = matrix[n-1-y][x];matrix[n-1-y][x] = matrix[n-1-x][n-1-y];matrix[n-1-x][n-1-y] = matrix[y][n-1-x];matrix[y][n-1-x] = flag;}}}
};
方法三:用翻轉代替旋轉

時間復雜度 O(n^2),空間復雜度 O(1)

class Solution {
public:void rotate(vector<vector<int>>& matrix) {int n = matrix.size();for(int x=0; x<n/2; ++x){for(int y=0; y<n; ++y){swap(matrix[x][y], matrix[n-1-x][y]);}}for(int x=0; x<n; ++x){for(int y=0; y<x; ++y){swap(matrix[x][y], matrix[y][x]);}}}
};

04 搜索二維矩陣 Ⅱ

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {}
};
方法一:直接查找

時間復雜度 O(mn),空間復雜度 O(1)

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {for(const auto& row: matrix){for(int element: row){if(element == target) return true;}}return false;}
};
方法二:二分法

時間復雜度 O(mlogn),空間復雜度 O(1)

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {for(const auto& row: matrix){auto it = lower_bound(row.begin(), row.end(), target);if(it != row.end() && *it == target) return true;}return false;}
};

lower_bound?是一個標準庫函數,位于 <algorithm>?頭文件中,用于在一個已排序的范圍內查找目標值的位置。lower_bound?返回一個迭代器,指向范圍內第一個不小于目標值的元素的位置,如果所有的元素都小于目標值,它將返回指向末尾的迭代器。

注意:使用 lower_bound? 的前提是 row 必須是排序好的,否則結果是不確定的。

方法三:Z字形查找
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int m = matrix.size(), n = matrix[0].size();int x = 0, y = n-1;while(x < m && y >=0){if(matrix[x][y] == target) return true;else if(matrix[x][y] > target) y--;else x++;}return false;}
};

文章部分代碼來源于力扣(LeetCode)

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

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

相關文章

Java【網絡原理】(3)網絡編程續

目錄 1.前言 2.正文 2.1ServerSocket類 2.2Socket類 2.3Tcp回顯服務器 2.3.1TcpEchoServer 2.3.2TcpEchoClient 3.小結 1.前言 哈嘍大家好&#xff0c;今天繼續進行計算機網絡的初階學習&#xff0c;今天學習的是tcp回顯服務器的實現&#xff0c;正文開始 2.正文 在…

C++11新特性 8.final關鍵字、override關鍵字

一.final 用法&#xff1a; 1.修飾函數 只能修飾虛函數&#xff0c;阻止子類重寫這個函數&#xff0c;final關鍵字寫在函數名的后面。 即該虛函數不可以再被重寫。 注意&#xff1a;一般不會在基類中使用&#xff0c;不然沒有意義&#xff0c;因為只能修飾虛函數。 2.修飾…

Python實現網絡通信:Socket模塊與TCP/IP協議全解析

Langchain系列文章目錄 01-玩轉LangChain&#xff1a;從模型調用到Prompt模板與輸出解析的完整指南 02-玩轉 LangChain Memory 模塊&#xff1a;四種記憶類型詳解及應用場景全覆蓋 03-全面掌握 LangChain&#xff1a;從核心鏈條構建到動態任務分配的實戰指南 04-玩轉 LangChai…

click house擴容方案

《ClickHouse擴容方案解析》 當我們談論數據庫的時候&#xff0c;尤其是像ClickHouse這樣專為處理大規模數據分析而設計的列式存儲數據庫時&#xff0c;擴容是一個不可避免的話題。隨著數據量的增長和查詢復雜度的提升&#xff0c;原有的硬件資源可能不足以支撐高效的查詢響應…

【AGI】智譜開源2025:一場AI技術民主化的革命正在到來

智譜開源2025&#xff1a;一場AI技術民主化的革命正在到來 引言&#xff1a;開源&#xff0c;一場技術平權的革命一、CogView4&#xff1a;中文AI生成的里程碑1. 破解漢字生成的“AI魔咒”2. 開源協議與生態賦能 二、AutoGLM&#xff1a;人機交互的范式躍遷1. 自然語言驅動的跨…

java8中young gc的垃圾回收器選型,您了解嘛

在 Java 8 的 Young GC&#xff08;新生代垃圾回收&#xff09;場景中&#xff0c;對于 ToC的場景&#xff0c;即需要盡可能減少垃圾回收停頓時間以滿足業務響應要求的場景&#xff0c;以下幾種收集器各有特點&#xff0c;通常 Parnew和 G1 young表現較為出色&#xff0c;下面詳…

【數學 矩陣快速冪】P7108 移花接木|普及+

本文涉及知識點 數學 移花接木 題目背景 遙遠的圣地生長著一棵不為人知的靈樹&#xff0c;或有萬山之高。 但有一日&#xff0c;藏匿于根系的腐朽力量爆發&#xff0c;靈樹已無法支撐往日屹立沖天的高度。 題目描述 靈樹最初的形態可以看作一棵高度為 10 10 10 10 {10}…

2025-03-09 學習記錄--C/C++-PTA 習題10-7 十進制轉換二進制

合抱之木&#xff0c;生于毫末&#xff1b;九層之臺&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、題目描述 ?? 裁判測試程序樣例&#xff1a; #include <stdio.h>void dectobin( int n );int main() {int n;scanf(…

前端 | CORS 跨域問題解決

問題&#xff1a;Access to fetch at http://localhost:3000/save from origin http://localhost:5174 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the request…

fastapi房產銷售系統

說明&#xff1a; 我希望用fastapi寫幾個接口&#xff0c;查詢房產交易系統的幾條數據&#xff0c;然后在postman里面測試 查詢客戶所有預約記錄&#xff08;含房源信息&#xff09;需要對應銷售經理查詢客戶所有訂單&#xff08;含房源信息&#xff09;統計銷售經理名下所有房…

導軌式ARM工業控制器:組態軟件平臺的“神經中樞”

工業自動化領域&#xff0c;組態軟件平臺扮演著至關重要的角色。它不僅是工業控制系統的“大腦”&#xff0c;更是實現智能化、高效化生產的關鍵工具。而作為組態軟件平臺的硬件支撐&#xff0c;導軌式ARM工控機&#xff08;以下簡稱“工控機”&#xff09;憑借其緊湊的設計、強…

每日一題——矩陣置零問題的原地算法

矩陣置零問題的原地算法 問題描述示例約束條件進階要求 問題分析難點分析解題思路 代碼實現代碼說明 測試用例測試用例 1測試用例 2測試用例 3 總結 問題描述 給定一個 m x n 的矩陣&#xff0c;如果矩陣中的某個元素為 0&#xff0c;則需要將其所在的行和列的所有元素都置為 …

Springboot中的@Value注解:用法與潛在問題探索

在Spring Boot開發中&#xff0c;有個非常實用的注解&#xff0c;那就是Value&#xff01;它可以幫助我們輕松地從配置文件中讀取屬性值。想象一下&#xff0c;在應用程序中管理各種配置&#xff0c;比如數據庫連接信息、服務URL或者API密鑰等&#xff0c;使用Value是多么方便呀…

C++后端服務器開發技術棧有哪些?有哪些資源或開源庫拿來用?

一、 C后臺服務器開發是一個涉及多方面技術選擇的復雜領域&#xff0c;特別是在高性能、高并發的場景下。以下是C后臺服務器開發的一種常見技術路線&#xff0c;涵蓋了從基礎到高級的技術棧。 1. 基礎技術棧 C標準庫 C11/C14/C17/C20&#xff1a;使用現代C特性&#xff0c;如…

25年攜程校招社招求職能力北森測評材料計算部分:備考要點與誤區解析

在求職過程中&#xff0c;能力測評是篩選候選人的重要環節之一。對于攜程這樣的知名企業&#xff0c;其能力測評中的材料計算部分尤為關鍵。許多求職者在備考時容易陷入誤區&#xff0c;導致在考試中表現不佳。本文將深入解析材料計算部分的實際考察方向&#xff0c;并提供針對…

golang進階知識專項-理解值傳遞

在 Go 語言中&#xff0c;所有函數的參數傳遞都是值傳遞&#xff08;Pass by Value&#xff09;。當你將一個變量作為參數傳遞給函數時&#xff0c;實際上傳遞的是該變量的副本&#xff0c;而不是變量本身。理解這一點對于避免常見的編程錯誤至關重要。根據不同的類型&#xff…

RuoYi框架添加自己的模塊(學生管理系統CRUD)

RuoYi框架添加自己的模塊&#xff08;學生管理系統&#xff09; 框架順利運行 首先肯定要順利運行框架了&#xff0c;這個我不多說了 設計數據庫表 在ry數據庫中添加表tb_student 表字段如圖所示 如圖所示 注意id字段是自增的 注釋部分是后面成功后前端要展示的部分 導入…

中級網絡工程師面試題參考示例(1)

一、基礎理論 1. OSI七層模型與TCP/IP四層模型的區別是什么&#xff1f;請舉例說明第三層&#xff08;網絡層&#xff09;和第四層&#xff08;傳輸層&#xff09;的核心協議。 參考答案&#xff1a; OSI七層模型分為物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用…

RHCE9.0版本筆記5:防火墻的本地/遠程登錄方式

一、防火墻登錄方式全景圖 華為防火墻支持多種管理訪問方式&#xff0c;根據安全等級和場景需求可分為&#xff1a; graph LR A[管理方式] --> B[本地登錄] A --> C[遠程登錄] B --> B1(Console) B --> B2(Web) C --> C1(SSH) C --> C2(Telnet) C --> C…

2025最新群智能優化算法:山羊優化算法(Goat Optimization Algorithm, GOA)求解23個經典函數測試集,MATLAB

一、山羊優化算法 山羊優化算法&#xff08;Goat Optimization Algorithm, GOA&#xff09;是2025年提出的一種新型生物啟發式元啟發式算法&#xff0c;靈感來源于山羊在惡劣和資源有限環境中的適應性行為。該算法旨在通過模擬山羊的覓食策略、移動模式和躲避寄生蟲的能力&…