蛇形矩陣

開始了找工作的一年,刷題的過程中發現有時候好記性不如爛筆頭,而且有時候找最好的解法並不容易,因此,陸續更新一些筆記,方便和我一樣的小白們學習。

蛇形矩陣是很常見的題目,我在這裏給出見到的幾種變種題型及其較爲簡潔的解法。

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矩陣,最外面的循環包含了八個數,最裏面的數其實只需要左上到右上就行了。四分之一圈。


綜上,這就是我遇到的蛇形矩陣的幾種變種,比較簡單。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章