对角线打印二维数组问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiyei2009/article/details/80295930

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("");
    }

输出结果:

扫描二维码关注公众号,回复: 3859994 查看本文章
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

猜你喜欢

转载自blog.csdn.net/qiyei2009/article/details/80295930