開始了找工作的一年,刷題的過程中發現有時候好記性不如爛筆頭,而且有時候找最好的解法並不容易,因此,陸續更新一些筆記,方便和我一樣的小白們學習。
蛇形矩陣是很常見的題目,我在這裏給出見到的幾種變種題型及其較爲簡潔的解法。
1.首先,最常規的題目是讓你輸出一個大小爲n的方陣:大概長這樣:
這是一個邊長爲5的蛇形矩陣,按照對角線方向依次遞增。
直接上代碼:
#include <iostream>
using namespace std;
void snakeLikeMat(int **a, int n)
{
int num = 1;
int total = n*n;
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
if (i % 2==1)
{
a[j][i - j] = num++;
}
else
{
a[i - j][j] = num++;
}
}
}
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j <= i; j++)
{
if (i % 2==1)
{
a[n - 1 - j][n - 1 - i + j] = total--;
}
else
{
a[n - 1 - i + j][n - 1 - j] = total--;
}
}
}
}
int main()
{
int ha = 0;
cin >> ha;
int **a = new int*[ha];
for (int i = 0; i < ha; i++)
{
a[i] = new int[ha];
}
snakeLikeMat(a, ha);
for (int i = 0; i < ha; i++)
{
for (int j = 0; j < ha; j++)
{
if (a[i][j] > 0 && a[i][j] <= ha*ha){
cout << a[i][j] << "\t";
}
else cout << " " << "\t";
}
cout << endl;
}
for (int i = 0; i < ha; i++)
{
delete[] a[i];
}
delete[] a;
system("pause");
關鍵部分就是snakeLikeMat。它將整個矩陣分成對角線以上和對角線以下分別賦值。
我們知道,每個對角線上的元素的關係是,它們的橫縱座標之和相等,這也是a[j][i - j]的道理,左上角的一半,第i個對角線和爲i。右下角的一半,和爲2n-2+i,注意這裏是從右下角開始的。
而i%2==1則是因爲奇數對角線和偶數對角線的方向是相反的。
2.變種,半蛇形矩陣,這時候只要去掉那個嵌套循環就行,上半角就去掉第二個,下半角去掉第一個
3.變種,第一個值首先向下還是向右發展。這時候改成i%2==0就行
4.變種,有時候有些題也會把螺旋矩陣叫成蛇形矩陣,大概長這樣:
直接上代碼:
#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
const int maxn = 10;
int a[maxn][maxn];
int main()
{
int n,m;
cin >> n>>m;
int tot, x, y;
memset(a, 0, sizeof(a));
tot = a[x = 0][y = 0] = 1;
while (tot<n*m)
{
while (y + 1<n&&!a[x][y + 1])a[x][++y] = ++tot;
while (x + 1<m&&!a[x + 1][y])a[++x][y] = ++tot;
while (y - 1 >= 0 && !a[x][y - 1])a[x][--y] = ++tot;
while (x - 1 >= 0 && !a[x - 1][y])a[--x][y] = ++tot;
}
for (x = 0; x<m; x++)
{
for (y = 0; y<n; y++)
printf("%3d", a[x][y]);
cout << endl;
}
system("pause");
}
代碼是改編過的,可以不是一個方陣,同時這也並不是常規寫法。
首先,用memset函數設置了一個m*n的全0矩陣,並將a[0][0]賦值爲1。
然後用一個嵌套循環,讓其賦值。按照一圈,從左上到右上,從右上到右下,從右下到左下,從左下到左上的順序完成一圈。裏面的while檢驗兩個條件:一是即將賦值的這個位置是否還在矩陣範圍內,二是這個位置是否已經被賦值過了,其中第二個條件的存在使得其循環完最外圈後開始循環次外圈,然後一直循環,直到某個賦值是該矩陣中的最後一個值:m*n。
5.變種,讓你按照螺旋的順序輸出某個矩陣,與4類似,這裏用常規思路寫
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
int row = matrix.size();
int col = matrix[0].size();
vector<int> res;
// 輸入的二維數組非法,返回空的數組
if (row == 0 || col == 0) return res;
// 定義四個關鍵變量,表示左上和右下的打印範圍
int left = 0, top = 0, right = col - 1, bottom = row - 1;
while (left <= right && top <= bottom)
{
// left to right
for (int i = left; i <= right; ++i) res.push_back(matrix[top][i]);
// top to bottom
for (int i = top + 1; i <= bottom; ++i) res.push_back(matrix[i][right]);
// right to left
if (top != bottom)
for (int i = right - 1; i >= left; --i) res.push_back(matrix[bottom][i]);
// bottom to top
if (left != right)
for (int i = bottom - 1; i > top; --i) res.push_back(matrix[i][left]);
left++,top++,right--,bottom--;
}
return res;
}
};
簡單來說,定義了四個值:左、右、上、下,每過一次循環,則左+1、右-1、上+1、下-1,進行下一圈,和上面的寫法不同,這裏進入下一圈是由四個值控制的。
其中的重點是兩個if語句,if (top != bottom)以及if (left != right)用來判斷是否需要再循環,因爲奇數情況下最內層的循環可能只有半圈或者四分之一圈,不要重複。比如3*3矩陣,最外面的循環包含了八個數,最裏面的數其實只需要左上到右上就行了。四分之一圈。
綜上,這就是我遇到的蛇形矩陣的幾種變種,比較簡單。