二维数组简介篇中同样有三道经典的算法题:对角线遍历,螺旋矩阵和杨辉三角。
对角线遍历
题目描述:
给定一个含有 M x N 个元素的矩阵(M行,N列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。
示例:
输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,4,7,5,3,6,8,9]
解释:
说明:
给定矩阵中的元素总数不会超过 100000 。
解题思路:
1.从箭头的方向上来看,无非两种:右上(↗)和左下(↙)
2.右上:行数减1,列数加1
左下:行数加1,列数减1
3.↗的过程中,若此时已经是第一行了,则需要改变方向,此时还需考虑两种情况:
若不在最后一列,则行数不变,列数加1,方向改为↙
若此时已经在最后一列,则行数加1,列数不变,方向改为↙
4.↙左下的过程中,若此时已经是第一列了,则需要改变方向,此时也需要考虑两种情况:
若不在最后一行,则列数不变,行数加1,方向改为↗
若此时已经在最后一行,则行数不变,列数加1,方向改为↗
代码:
public static int[] findDiagonalOrder(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
int currentRow = 0;
int currentCol = 0;
boolean up = true;
int[] result = new int[rows * cols];
for (int i = 0; i < rows * cols; i++) {
result[i] = matrix[currentRow][currentCol];
if (up) {//右上
if (currentRow - 1 >= 0 && currentCol + 1 < cols) {
currentCol++;
currentRow--;
} else if (currentCol + 1 < cols) {
currentCol++;
up = false;
} else {
currentRow++;
up = false;
}
} else {//左下
if (currentCol - 1 >= 0 && currentRow + 1 < rows) {
currentCol--;
currentRow++;
} else if (currentRow + 1 < rows) {
currentRow++;
up = true;
} else {
currentCol++;
up = true;
}
}
}
return result;
}
螺旋矩阵
题目描述:
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例 1:
输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] 输出: [1,2,3,6,9,8,7,4,5]
示例 2:
输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出: [1,2,3,4,8,12,11,10,9,5,6,7]
解题思路:
1.若输入的矩阵长度为1,或者每个子数组中只有一个元素,直接遍历即可
2.从起点开始,在顺时针中的方向顺序依次为→,↓,←,↑ ,根据这四种情况改变行和列:
→ :遍历这一行的元素,即行数不变,列数不断加1,直到下一个元素是最后一列
↓ :遍历这一列的元素,即列数不变,行数不断加1,直到下一个元素是最后一行
← :遍历这一行的元素,即行数不变,列数不断减1,直到下一个元素是第一列
↑ : 遍历这一列的元素,即列数不变,行数不断减1,直到下一个元素是第一列行
3.走完上面这步之后,已经顺时针转了一圈,此时则要更新将下一圈的起始点
举个例子:第一圈的时候起始点是(0,0),第二圈就是(1,1)
4.走到终点时要记得跳出循环
代码:
public static List<Integer> spiralOrder(int[][] matrix){
if (matrix.length == 0){
return new ArrayList<>();
}
int cols = matrix[0].length;
int rows = matrix.length;
int currentRow = 0;
int currentCol = 0;
List<Integer> result = new ArrayList<>();
while (rows>0 && cols >0){
if (cols == 1){
for (int i = 0; i < rows ; i++) {
result.add(matrix[currentRow++][currentCol]);
}
return result;
}
if (rows == 1){
for (int i = 0; i <cols ; i++) {
result.add(matrix[currentRow][currentCol++]);
}
return result;
}
//→
for (int i = 0; i <cols-1 ; i++) {
result.add(matrix[currentRow][currentCol++]);
}
//↓
for (int i = 0; i <rows-1 ; i++) {
result.add(matrix[currentRow++][currentCol]);
}
//←
for (int i = 0; i <cols-1 ; i++) {
result.add(matrix[currentRow][currentCol--]);
}
//↑
for (int i = 0; i <rows-1 ; i++) {
result.add(matrix[currentRow--][currentCol]);
}
currentRow ++;
currentCol ++;
cols -= 2;
rows -= 2;
}
return result;
}
杨辉三角
题目描述:
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ]
解题思路:
1.每一行的头尾两个数肯定都为1,先让每一行的数字全为1
2.从第三行才开始调整中间的数
代码
public static List<List<Integer>> generate(int numRows) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
for(int i=0;i<numRows;i++){
temp.add(1);
for(int j=i-1;j>0;j--){
temp.set(j,temp.get(j)+temp.get(j-1));
}
result.add(new ArrayList<>(temp));
}
return result;
}