开始了找工作的一年,刷题的过程中发现有时候好记性不如烂笔头,而且有时候找最好的解法并不容易,因此,陆续更新一些笔记,方便和我一样的小白们学习。
蛇形矩阵是很常见的题目,我在这里给出见到的几种变种题型及其较为简洁的解法。
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矩阵,最外面的循环包含了八个数,最里面的数其实只需要左上到右上就行了。四分之一圈。
综上,这就是我遇到的蛇形矩阵的几种变种,比较简单。