整体算法思想来自:
【【寒假每日一题】Day-3(《 756. 蛇形矩阵》偏移量技巧)】 https://www.bilibili.com/video/BV1mK411M7Ng/?share_source=copy_web&vd_source=fe1ac3bec858ccd7b6481fa1ea1d9820
目录
偏移量法
偏移量法的核心思想是使用两个数组来控制遍历方向。这种方法特别适合于遍历二维空间时的方向控制。
如何定义dx、dy数组?
矩阵遍历使用的x和y的定义有些特殊。通常,在数学和计算机图形学中,我们习惯于将x轴定义为水平方向,y轴定义为垂直方向。然而,在二维数组或矩阵的上下文中,这些轴的定义通常与传统的笛卡尔坐标系有所不同。
- 在代码中
- x变量代表的是二维数组的行索引。
- y变量代表的是二维数组的列索引。
然而,
- 当我们说“向上”移动时,实际上是在减少x的值(因为在数组中向上移动意味着向更小的行索引移动)。所以对应的坐标变为:(x-1 , y)
- 同样,"向右"移动实际上是增加y的值(在数组中向右移动意味着向更大的列索引移动)。所以对应的坐标变为:(x , y+1)
- “向下”移动是增加x的值。所以对应的坐标变为:(x+1 , y)
- “向左”移动是减少y的值。这种定义方式是基于二维数组的索引,其中matrix[x][y]表示位于第x行和第y列的元素。
所以,尽管这种定义方式可能与传统的笛卡尔坐标系不同,但它完全适合于二维数组或矩阵的遍历操作。
实例(图解)
在这里给出一个例子:
列出针对(x,y)上下左右的偏移量数组
偏移量按照“上、右、下、左”的顺序来定义的。这个顺序决定了遍历矩阵的方向。
在代码中:
dx = {-1, 0, 1, 0} 表示行的变化。
dy = {0, 1, 0, -1} 表示列的变化。
这里的偏移量对应的遍历方向是:
- 向上(dx = -1, dy = 0)。
- 向右(dx = 0, dy = 1)。
- 向下(dx = 1, dy = 0)。
- 向左(dx = 0, dy = -1)。
在遍历过程中,通过改变d的值来选择不同的偏移量,从而改变遍历的方向。遍历始于向右方向(d = 1),并在遇到边界或已访问的元素时顺时针旋转到下一个方向。
这种方法特别适合处理这类二维数组遍历的问题。通过简单地调整偏移量数组,可以轻松地更改遍历的方向或模式,适应各种不同的需求和场景。
模板
偏移量法的核心在于定义一组方向向量,通过这些向量控制遍历的方向。这种方法的模板化可以分为以下几个步骤:
- 定义方向向量:创建两个数组,一个表示行的偏移(dx),另一个表示列的偏移(dy)。例如,对于上、右、下、左的顺时针方向,可以定义dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1}。
- 初始化遍历状态:设置起始点和初始方向,通常从(0,0)点开始,方向设置为向右。
- 遍历矩阵:使用一个循环进行遍历,每次移动后检查边界和是否已访问,必要时改变方向。
- 边界和访问状态检查:在每次移动后,检查下一个位置是否超出矩阵边界或者已经访问过。如果是,改变方向。
实战(做题)
链接
题目
//acwing
//756.蛇形矩阵
//矩阵偏移量
//dx[4] ={-1,0,1,0}
//dy[4]={0,1,0,-1}
#include<iostream>
using namespace std;
const int N = 110;
int n, m;
int res[N][N];
int main()
{
cin >> n >> m;
//偏移量数组(上下左右方向)
int dx[] = { -1,0,1,0 }, dy[] = { 0,1,0,-1 };
int dir = 1; //移动方向
int x = 0, y = 0; //起始位置(0,0)
for (int i = 1; i <= n * m; i++) //填充遍历
{
res[x][y] = i;//填充
int a = x + dx[dir], b = y + dy[dir]; //使用临时变量,进行边界检查
//边界检测----需要转向
//在矩阵边缘-->转向
//重复下标---> 转向
//为什么会出现res[a][b]这个条件?
//1.res[a][b] 检查重复下标
//c++中,全局数组变量(非vector)的初始化默认是0。
//而0可以被认为是false
if (a < 0 || a >= n || b < 0 || b >= m || res[a][b]) //判断行走的下一个状态是否碰壁
//( 下移时是否碰越下界 || 右移时是否越右界 || 左移时是否越左界) || (若不改变移动方向 下一点是否已经到达过)
{
dir = (dir + 1) % 4;
a = x + dx[dir], b = y + dy[dir];
}
x = a;
y = b;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cout << res[i][j] << " ";
}
cout << endl;
}
return 0;
}