二維矩陣的有套路嗎?當然有,但是不如回溯、貪心這類題有模板,但是很多題的思路可以舉一反三的
目錄
先遍歷記錄在清零的福利題:LeetCode.73矩陣置零&&面試題01.08.零矩陣
先遍歷記錄在清零的福利題:LeetCode.73矩陣置零&&面試題01.08.零矩陣
思路有很多種,但是最後的複雜度都一樣O(M+N)
這裏使用的是先記錄要清零的行數和列數,再遍歷一遍進行清零
當然,拿到這題首先的思路是:呵呵,邊遍歷邊清零不行麼?當然不行,這樣會影響下一個判斷!
高讚的思路:
空間複雜度 O(2) ,用兩個布爾變量就可以解決。方法就是利用數組的首行和首列來記錄 0 值。從數組下標的 A[1][1] 開始遍歷,兩個布爾值記錄首行首列是否需要置0。
這種思路和上面的大同小異,只是充分利用的矩陣的首行和首列,降低了空間複雜度
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
// 開闢兩個一維數組存放要清零的行和列
bool col[matrix.size()];
bool row[matrix[0].size()];
// 初始化
for(int i = 0; i<matrix.size(); i++)
col[i] = false;
for(int j = 0; j<matrix[0].size(); j++)
row[j] = false;
// 遍歷記錄
for(int i = 0; i<matrix.size(); i++) {
for(int j = 0; j<matrix[0].size(); j++) {
if(matrix[i][j] == 0) {
col[i] = true;
row[j] = true;
}
}
}
// 將這一行清零
for(int i = 0; i<matrix.size(); i++) {
if(col[i]) {
for(int j = 0; j<matrix[0].size(); j++) {
matrix[i][j] = 0;
}
}
}
// 將這一列清零
for(int j = 0; j<matrix[0].size(); j++) {
if(row[j]){
for(int i = 0; i<matrix.size(); i++) {
matrix[i][j] = 0;
}
}
}
return;
}
};
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
// 開兩個數組分別記錄需要置零的行和列
bool col[matrix.size()];
bool row[matrix[0].size()];
// 先初始化數組
for(int i = 0; i<matrix.size(); i++)
col[i] = false;
for(int i = 0; i<matrix[0].size(); i++)
row[i] = false;
// 遍歷一般進行查找需要置零的行和列
for(int i = 0; i<matrix.size(); i++)
for(int j = 0; j<matrix[0].size(); j++)
if(matrix[i][j] == 0) {
col[i] = true;
row[j] = true;
}
// 分別遍歷行和列進行判斷與置零
for(int i = 0; i<matrix.size(); i++)
if(col[i])
for(int j = 0; j<matrix[0].size(); j++)
matrix[i][j] = 0;
for(int j = 0; j<matrix[0].size(); j++)
if(row[j])
for(int i = 0; i<matrix.size(); i++)
matrix[i][j] = 0;
}
};
二維矩陣中的經典:LeetCode54.螺旋矩陣
這道題的思路很清晰,但是一次AC難度可不小,可以當做一個經典模板題來處理!
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
if(matrix.empty()||matrix[0].empty())
return ans;
int up = 0, down = matrix.size()-1, left = 0, right = matrix[0].size()-1;
while (true) {
for(int i = left; i<=right; i++)
ans.push_back(matrix[up][i]);
if(++up>down)
break;
for(int i = up; i<=down; i++)
ans.push_back(matrix[i][right]);
if(--right<left)
break;
for(int i = right; i>=left; i--)
ans.push_back(matrix[down][i]);
if(--down<up)
break;
for(int i = down; i>=up; i--)
ans.push_back(matrix[i][left]);
if(++left>right)
break;
}
return ans;
}
};
劍指offer經典:LeetCode74.搜索二維矩陣
思路就是利用升序矩陣的性質,從右上角開始搜索,總的複雜度O(M+N),還是比較理想的
這道題刷過劍指offer應該印象深刻吧!
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size()==0)
return false;
int i = 0;
int j = matrix[0].size()-1;
while (i<matrix.size()&&j>=0) {
if ( matrix[i][j]>target ) {
j--;
}else if (matrix[i][j]<target) {
i++;
}else {
return true;
}
}
return false;
}
};
類似上一題的:LeetCode240.搜索二維矩陣II
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size()==0)
return false;
// 使用雙指針從右上角進行查找
int i = 0;
int j = matrix[0].size()-1;
while (i<matrix.size()&&j>=0) {
if(matrix[i][j]>target) {
j--;
}else if(matrix[i][j]<target) {
i++;
}else{
return true;
}
}
return false;
}
};
二維二分法:LeetCode378.有序矩陣中第K小的元素
這個二分比較難,思路上比較難
二分的基準是以整個矩陣中的mid,以這個mid統計矩陣有多少個數大於mid,多少個數小於mid
當然,在尋找mid的過程也要利用排序矩陣的性質
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int row = matrix.size();
int col = matrix[0].size();
int left = matrix[0][0];
int right = matrix[row-1][col-1];
while (left<right) {
// 每次循環都保證第K小的數在start~end之間,當start==end,第k小的數就是start
int mid = (left+right)/2;
// 找二維矩陣中<=mid的元素總個數
int count = findSmallThanMid(matrix, mid, row, col);
if (count < k) {
// 第k小的數在右半部分,且不包含mid
left = mid+1;
}else {
// 第k小的數在左半部分,可能包含mid
right = mid;
}
}
return right;
}
private:
// 以列爲單位找,找到每一列最後一個<=mid的數即知道每一列有多少個數<=mid
int findSmallThanMid(vector<vector<int>> & matrix, int mid, int row, int col) {
int i = row-1;
int j = 0;
int count = 0;
while (i>=0 && j < col) {
if (matrix[i][j] <= mid) {
count += i+1;
j++;
}else {
i--;
}
}
return count;
}
};
LeetCode.面試01.07.旋轉矩陣
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
if(matrix.size()==0||matrix.size()!=matrix[0].size())
return;
int n = matrix.size();
for(int layer = 0;layer<n/2;layer++){
int first = layer;
int last = n-1-layer;
for(int i=first;i<last;i++){
int offset = i-first;
int top = matrix[first][i];//存儲上邊
//左邊移動到上邊
matrix[first][i] = matrix[last-offset][first];
//下邊移動到左邊
matrix[last-offset][first] = matrix[last][last-offset];
//右邊移動到下邊
matrix[last][last-offset] = matrix[i][last];
//上邊移動到右邊
matrix[i][last] = top;
}
}
return;
}
};