概述
1 前言
最近在网上看到这样一道面试题:二维数组(N*N),沿对角线方向,从右上角打印到左下角如N=4:
4*4二维数组
{ 1 2 3 4 }
{ 5 6 7 8 }
{ 9 10 11 12 }
{13 14 15 16 }
打印顺序
4
3 8
2 7 12
1 6 11 16
5 10 15
9 14
13
网上已经有各种解法,也有现成的程序,但是个人都不是很满意,网络上的思路都不是很清晰。现在提供一种分析思路及源代码
2 分析思路
对于一个二维数组,我们画出示意图如下:
当column = row时,就是一个方正的数组,我们现在来考虑如何打印符合题目要求的。
其实这个问题优一种很简单的解法,就是在数很小时,写出每个打印的坐标,然后来找规律。但是我觉得不够好,我们先来画出题目要求打出的顺序的示意图。(4 X 4 数组)
根据示意图,我们可以分两步来考虑这个问题。
第一步:先打印那四根黑色的线串联起来的元素。如果我们按照逆时针的方向来串联元素,那么就有如下的示意图:
0轮打印 3
1轮打印 2 7
2轮打印 1 6 11
。。。
假设数组有n * n 大小,k从 n-1 循环到 0
(n-1 - k) 轮打印为 a[0][k] a[1][k + 1] ….a[n-1 - k][n-1] ,那么对于每一轮打印,我们就有以下代码
我们可以认为,第一步就是从n - 1列遍历到0列
//右上角,我们可以认为先从n - 1 到 0 列
for (int k = n - 1 ; k >= 0; k--){
//每一列的循环 行下标i会增加,列下标j会增加
for (i = 0 ,j = k; i <= n - 1 - k && j <= n - 1 ; i++,j++){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
第二步:处理到了0这个对角线之后,我们可以看蓝色的三根线,这里我们可以认为从1 行遍历到n -1行,那么k从1 循环到n-1
k轮:a[k][0] a[k+1][1] … a[n-1][n-1 - k]
//再从1 到 n - 1 行
for (int k = 1 ; k <= n - 1; k++){
//每一列的循环 行下标i会增加,列下标j会增加
for (i = k ,j = 0; i <= n - 1 && j <= n - 1 - k ; i++,j++){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
这样将两个循环合并在一起,我们就认为,我们把这个数组按照从右上角对角线打印全部打印完了。
/**
* 左上角开始打印二维矩阵数组
* @param array
*/
private static void printTwoDimensionalArrayTopRight(int[][] array){
int n = array.length;
int maxSize = n * n;
int len = (maxSize + "").length();
//初始角标
int i = 0;
int j = 0;
//右上角,我们可以认为先从n - 1 到 0 列
for (int k = n - 1 ; k >= 0; k--){
//每一列的循环 行下标i会增加,列下标j会增加
for (i = 0 ,j = k; i <= n - 1 - k && j <= n - 1 ; i++,j++){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
//再从1 到 n - 1 行
for (int k = 1 ; k <= n - 1; k++){
//每一列的循环 行下标i会增加,列下标j会增加
for (i = k ,j = 0; i <= n - 1 && j <= n - 1 - k ; i++,j++){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
LogUtil.println("");
}
运行开始的题目,我们能得到的输出结果如下:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
4
3 8
2 7 12
1 6 11 16
5 10 15
9 14
13
3 拓展
我们再来看看之前的分析思路:
1 首先看箭头:方向为右下,根据数组坐标系原则,我们可以知道a[i][j]在每一轮内循环中都会自增.
只需要知道初始a[i][j]与结束a[i][j]时就可以开始循环了
2 对于右上角开始的对角线打印,我们按照逆时针的方向来看,先从n - 1 到 0 列,再从1 行到n行。
n - 1 到 0 列 起点坐标为:a[0][k] 终点坐标:a[n - 1 - k][n-1] i++,j++ k从n-1循环到0
1 到 n -1 行 起点坐标为:a[k][0] 终点坐标:a[n - 1][n-1 - k] i++,j++ k从1循环到n-1
类似的,如果我们是从左上角开始打印呢?那么有如下的示意图:
1 根据箭头方向及数组坐标系,i++,j–
2 根据顺时针来看,先是0到n-1列,再是1到n-1行
0到n-1列 起点坐标a[0][k] 终点坐标a[k][0] k从0循环到n-1
1 到n-1行 起点坐标a[k][n-1] 终点坐标a[n-1][k] k从1循环到n-1
那么就有以下代码
/**
* 左上角开始打印二维矩阵数组,按照顺时针方向来选取
* @param array
*/
private static void printTwoDimensionalArrayTopLeft(int[][] array){
int n = array.length;
int maxSize = n * n;
int len = (maxSize + "").length();
//初始角标
int i = 0;
int j = 0;
//左上角,我们可以认为先从0 到 n - 1 列
for (int k = 0 ; k <= n - 1; k++){
//每一列的循环 行下标i会增加,列下标j会减少
for (i = 0 ,j = k; i <= k && j >= 0 ; i++,j--){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
//再从1 到 n - 1 行
for (int k = 1 ; k <= n - 1; k++){
//每一列的循环 行下标i会增加,列下标j会减少
for (i = k ,j = n - 1; i <= n - 1 && j >= k ; i++,j--){
LogUtil.print(getFixedLenString(array[i][j] + "",len," ") + " ");
}
//换行
LogUtil.println("");
}
LogUtil.println("");
}
输出结果:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
1
2 5
3 6 9
4 7 10 13
8 11 14
12 15
16
特别的对于左下角,右下角,我们都有对应的方法分析:
左下角:
1 根据箭头方向及数组坐标系,i++,j++
2 根据顺时针来看,先是n-1行到0行,再是1到n-1列
n-1行到0行 起点坐标a[k][0] 终点坐标a[n-1][n-1-k] k从n-1循环到0
1 到n-1列 起点坐标a[0][k] 终点坐标a[n-1-k][n-1] k从1循环到n-1
代码就不贴了
右下角:
1 根据箭头方向及数组坐标系,i++,j–
2 根据逆时针来看,先是n-1到0行,再是n-2到0列
n-1到0行 起点坐标a[k][n-1] 终点坐标a[n-1][k] k从0循环到n-1
n-2到0列 起点坐标a[0][k] 终点坐标a[k][0] k从n-2循环到0
代码就不贴了
最后:参考代码https://github.com/qiyei2015/Algorithms/tree/master/src/com/qiyei/array
最后
以上就是强健舞蹈为你收集整理的对角线打印二维数组问题的全部内容,希望文章能够帮你解决对角线打印二维数组问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复