如何斜着遍历一个二维数组

博客主要围绕二维数组斜向遍历展开。介绍了动态规划中对dp数组右上斜向遍历的情况,以5*5矩阵为例,详细推导了不考虑对角线、考虑对角线时的遍历代码,还提及遍历左下角、左上角、右下角的情况,且指出从顶点遍历只需稍作修改。

如何斜着遍历一个二维数组

动态规划中有的题往往需要对dp数组斜着遍历,例如dp[ i ][ j ]的值主要由dp[ i ][ j-1 ]和dp[ i+1 ][ j ]两个值的大小决定,即向右上斜着遍历。

n = len(dp)
for l in range(1, n):
	for i in range(n - l):
		j = l + i
		dp[i][j] .....

这样既可完成遍历
可以看一个5 * 5的矩阵
一个行,列都为5的矩阵
在上图中,如果不考虑中间的对角线,只看右上角的斜线的话,对于5*5的二维数组,有4条斜线,表示我们要遍历4次。所以在第一层循环中的代码为
for l in range(1, 5)

那么 l 的值分别为1,2, 3,4

再来看每次遍历时,行(i)的变化
在第一次遍历时(l = 1),i 的位置依次为 0 1 2 3,遍历4行(5-1);
在第二次遍历时(l = 2),i的位置依次为 0 1 2,遍历3行(5-2);
在第三次遍历时(l = 3),i的位置依次为 0 1,遍历2行(5-3);
在第四次遍历时(l = 4),i的位置依次为 0,遍历1行(5-4);
所以 i 的可选范围是在range(5 - l)之中的,即:
for i in range(5 - l)

然后来看看列(j)的位置变化
同上可知
j = 1 2 3 4
j = 2 3 4
j = 3 4
j = 4
把l, i, j按如下排列一下:
l = 1---------------2------3----- 4
i = 0 1 2 3; 0 1 2; 0 1; 0
j = 1 2 3 4; 2 3 4; 3 4; 4
是不是可以看出 j = l + i
把5给替换成n
如此就推算出了斜着遍历的代码。

如果需要考虑dp[i][i]该怎么写:

还是以一个5*5的二维数组来看,考虑对角线的话,遍历次数就从5-1次变成了5次
for l in range(5)

按照上面的推算方式
l = -----0----------1--------2-----3----4
i = 0 1 2 3 4; 0 1 2 3; 0 1 2; 0 1; 0
j = 0 1 2 3 4; 1 2 3 4; 2 3 4; 3 4; 4
把5换成n,可以得出

for l in range(n):
	for i in range(n - l):
		j =l + i
		dp[i][j] .....

那如果想遍历二维数组的左下角怎么办:

这里同样是从 5 * 5长度推算到 n * n的长度,过程不表

for l in range(n):
	for i in range(l, n):
		j = i - l
		dp[i][j].....

遍历二维数组的左上角:

for l in range(n-1, -1, -1):
	for i in range(l, -1, -1):
		j = l - i
		dp[i][j].....

遍历二维数组的右下角:

for l in range(n):
	for i in range(n-1, l-1, -1):
		j = n + l - i - 1
		dp[i][j].....

注意,这里无论是左上角还是右下角,所有的遍历方向都是从二维数组的左/右对角线开始的。如果想从顶点开始斜着遍历数组,把上面的代码稍微改一下即可。

### C++ 中实现斜着遍历二维数组 在 C++ 中,可以采用多种方式来实现对二维数组的斜向遍历。以下是基于已有引用内容以及标准编程实践的一种解决方案。 #### 方法描述 为了实现斜向遍历,通常需要考虑两种主要方向: 1. **从右上到左下的对角线**(即 `i - j` 值固定)。 2. **从左下到右上的对角线**(即 `i + j` 值固定)。 通过调整循环逻辑,可以在这些对角线上依次访问元素[^3]。 --- #### 示例代码 以下是一个完整的 C++ 程序示例: ```cpp #include <iostream> using namespace std; const int N = 5; // 定义二维数组大小 void diagonalTraverseRightToLeft() { cout << "从右上到左下的对角线遍历:" << endl; for (int sum = 0; sum <= 2 * N - 2; ++sum) { // 遍历每条对角线 for (int i = 0; i < N; ++i) { int j = sum - i; if (i >= 0 && j >= 0 && i < N && j < N) { // 检查索引有效性 cout << "(" << i << ", " << j << ") "; } } cout << endl; } } void diagonalTraverseLeftToRight() { cout << "\n从左下到右上的对角线遍历:" << endl; for (int diff = -(N - 1); diff <= N - 1; ++diff) { // 遍历每条对角线 for (int i = 0; i < N; ++i) { int j = i - diff; if (i >= 0 && j >= 0 && i < N && j < N) { // 检查索引有效性 cout << "(" << i << ", " << j << ") "; } } cout << endl; } } int main() { diagonalTraverseRightToLeft(); diagonalTraverseLeftToRight(); return 0; } ``` --- #### 关键点解析 1. 对于从右上到左下的对角线遍历,核心在于控制变量 `sum = i + j` 的变化范围为 `[0, 2*N-2]`。每次迭代时,计算对应的 `(i, j)` 并验证其合法性[^4]。 2. 对于从左下到右上的对角线遍历,则依赖於差值 `diff = i - j` 来定义对角线位置。这里的 `diff` 范围是从 `-N+1` 到 `N-1`。 3. 在实际应用中,可以根据具体需求修改上述逻辑中的条件判断部分,以适应不同形状或边界情况的数组。 --- ### 输出样例解释 假设输入的是一个 5×5 的矩阵,程序会分别打印两条路径上的坐标序列。例如: ``` 从右上到左下的对角线遍历: (0, 0) (1, 0) (0, 1) (2, 0) (1, 1) (0, 2) ... 从左下到右上的对角线遍历: ... ``` 这表明我们成功实现了按指定方向逐一对角线扫描的功能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值