本題並不涉及到什麼演算法,就是模擬過程,但卻十分考察對程式碼的掌控能力。
1.題目1:59. 螺旋矩陣 II
1.1.解法1:模擬
本題的重點還是像之前的“704.二分查詢”,堅持迴圈不變數原則,即在本題中遍歷每條邊時,堅持相同的原則。
如下是一個示例,即n=5,我們考慮根據圈數和邊數來進行遍歷:
由外圈到內圈,而邊的方向則為:①從左到右、②從上到下、③從右到左、④從下到上。
(1)從外圈到內圈:引入start變數作為“轉圈”開始的位置,初始時start的值為0;第二圈時,start的值為1。
(2)邊①②③④:這裡在遍歷每條邊時,始終堅持“左閉右開”,也就是遍歷①時1、2、3、4,遍歷②時5、6、7、8,遍歷③時9、10、11、12,遍歷④時13、14、15、16。透過offset來控制每條邊遍歷結束的位置(n-offset),相應第二圈時,offset的值+1。
(3)當n為奇數時,中間會剩下一個數,如圖中“25”,我們最後對中間數進行單獨賦值。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>nums(n, vector<int>(n, 0));
int loop = n / 2; // 要旋轉的圈數
int start = 0; // 起始位置
int offset = 1; // 控制每一條邊遍歷的長度,每次迴圈右邊界收縮一位
int count = 1; // 用於賦值
while (loop--) {
int j = start, i = start;
// 以下四個for迴圈即旋轉了一圈
// (1)從左向右
for (; j < n - offset; j++) {
nums[i][j] = count++;
}
// (2)從上向下
for (; i < n - offset; i++) {
nums[i][j] = count++;
}
// (3)從右向左
for (; j > start; j--) {
nums[i][j] = count++;
}
// (4)從下向上
for (; i > start; i--) {
nums[i][j] = count++;
}
start++; // 第二圈開始的時,起始位置要加1
offset += 1; // 控制每一圈裡每一條邊遍歷的長度
}
// 如果n為奇數的話,需要單獨給矩陣最中間的位置賦值
if (n % 2 == 1) nums[n / 2][n / 2] = count;
return nums;
}
};
● 時間複雜度:\(O(n^2)\)。
● 空間複雜度:\(O(1)\)。
2.題目2:54.螺旋矩陣
類似於59.螺旋矩陣II,但本題矩陣行列不一定相等,且要求順時針方向輸出指定的矩陣。
2.1.解法1:模擬
思路上和59.螺旋矩陣II相似,都是:由外圈到內圈,而邊的方向則為:①從左到右、②從上到下、③從右到左、④從下到上。
不過需要注意一點,因為行數列數不相等的情況下:
1.旋轉的圈數應為:min(列數,行數) / 2。
2.當min(列數,行數)為奇數時:
min(列數,行數) = 列數,即還剩餘一箇中間列沒有被遍歷到;
min(列數,行數) = 行數,即還剩餘一箇中間行沒有被遍歷到;
剩餘的中間行或是中間列還需要單獨去進行遍歷,按照題意填充到目標陣列中。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
vector<int>nums(m * n);
int start = 0;
int loop = min(m, n) / 2;
int count = 0;
int offset = 1;
int i, j;
while (loop --) {
i = start, j = start;
// (1)從左往右
for (; j < n - offset; j++) {
nums[count++] = matrix[i][j];
}
// (2)從上往下
for (; i < m - offset; i++) {
nums[count++] = matrix[i][j];
}
// (3)從右往左
for (; j > start; j--) {
nums[count++] = matrix[i][j];
}
// (4)從下往上
for (; i > start; i--) {
nums[count++] = matrix[i][j];
}
start++;
offset++;
}
int mid = min(m, n) / 2;
if (min(m, n) % 2) {
if (m > n) { // 剩下一個中間列
for (int i = mid; i < mid + m - n + 1; i++) {
nums[count++] = matrix[i][mid];
}
}
else { // 剩下一個中間行
for (int i = mid; i < mid + n - m + 1; i++) {
nums[count++] = matrix[mid][i];
}
}
}
return nums;
}
};
● 時間複雜度:\(O(n^2)\) 模擬遍歷二維矩陣的時間。
● 空間複雜度:\(O(1)\)。
2.2.解法2:模擬(簡潔)
這是力扣上某大佬的一種解法:
1.設定上下左右邊界。
2.從左向右,第一行已經遍歷完,便可以從中刪除,相當於重新定義上邊界。
3.如果重新定義的上邊界與下邊界交錯,表示遍歷結束,跳出迴圈,返回答案。
若不交錯,繼續向下、向左、向上遍歷,操作步驟同1.2。
4.迴圈以上步驟,直至兩邊界交錯,跳出迴圈,返回答案。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int>ans;
if (matrix.empty()) return ans;
int left = 0, right = matrix[0].size() - 1, top = 0, bottom = matrix.size() - 1;
while (true) {
// 1.從左向右
for (int i = left; i <= right; i++) {
ans.push_back(matrix[top][i]);
}
if (++top > bottom) break;
// 2.從上向下
for (int i = top; i <= bottom; i++) {
ans.push_back(matrix[i][right]);
}
if (--right < left) break;
// 3.從右向左
for (int i = right; i >= left; i--) {
ans.push_back(matrix[bottom][i]);
}
if (--bottom < top) break;
// 4.從下向上
for (int i = bottom; i >= top; i--) {
ans.push_back(matrix[i][left]);
}
if (++left > right) break;
}
return ans;
}
};
3.題目3:LCR 146. 螺旋遍歷二維陣列
這題的解法同54。
3.1.解法1:模擬
class Solution {
public:
vector<int> spiralArray(vector<vector<int>>& array) {
if (array.size() == 0 || array[0].size() == 0) return {};
int m = array.size(), n = array[0].size();
vector<int>nums(m * n);
int loop = min(m, n) / 2;
int start = 0;
int offset = 1;
int count = 0;
int i, j;
while (loop --) {
i = start, j = start;
for (; j < n - offset; j++) {
nums[count++] = array[i][j];
}
for (; i < m - offset; i++) {
nums[count++] = array[i][j];
}
for (; j > start; j--) {
nums[count++] = array[i][j];
}
for (; i > start; i--) {
nums[count++] = array[i][j];
}
start++;
offset++;
}
int mid = min(m, n) / 2;
if (min(m, n) % 2) {
if (m > n) {
for (int i = mid; i < mid + m - n + 1; i++) {
nums[count++] = array[i][mid];
}
}
else {
for (int i = mid; i < mid + n - m + 1; i++) {
nums[count++] = array[mid][i];
}
}
}
return nums;
}
};
● 時間複雜度:\(O(n^2)\) 模擬遍歷二維矩陣的時間。
● 空間複雜度:\(O(1)\)。