LeetCode-对角线遍历二维数组

五迷三道 提交于 2020-01-14 01:33:36

LeetCode-对角线遍历二维数组

刷了一道题,是关于二维数组的,我这是第一次做二维数组的题目,因为对二维数组的不熟悉导致思路比较乱,中途甚至想要放弃,直接找题解,最终花了好长时间才做出来.虽然效率比较低,但是我觉得还是有必要记录一下思考的过程.

题目描述

给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。

输入: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]

输出: [1,2,4,7,5,3,6,8,9]

解释: image

说明:

给定矩阵中的元素总数不会超过 100000 。

我的解法思路

有个开发经验比我丰富很多的同事告诉我,做功能的时候先不要想着一步到位,可以先把基本的功能做出来再一点一点加东西.深以为然.

这个问题是对角线遍历,那我们把问题按照这个思路分解一下就是遍历---对角线遍历---符合题目顺序的对角线遍历

第一步:遍历

先把这个二维数组遍历出来.

public int[] findDiagonalOrder(int[][] matrix) {
        int res0[] = new int[0];
        if(matrix.length==0) return res0;
        List<Integer> list = new ArrayList(); 
        for(int i=0;i<matrix.length;i++){
            for(int j=0;j<matrix[i].length;j++){
                list.add(matrix[i][j]);
            }
        }
        int res[] = new int[list.size()];
        for(int i=0;i<list.size();i++){
            res[i] = list.get(i);
        }
        return res;
    }

我的输入:

[[1,2,3],[4,5,6],[7,8,9]]

我的输出:

[1,2,3,4,5,6,7,8,9]

第二步:对角线遍历

这个遍历肯定不会是像题目中所示的那样,环形遍历,而是都是从右上角到左下角的遍历.

public int[] findDiagonalOrder(int[][] matrix) {
        int res0[] = new int[0];
        if(matrix.length==0) return res0;
        List<Integer> list = new ArrayList(); 
        for(int sum=0;sum<matrix.length+matrix[0].length-1;sum++){ //判断条件是matrix[x][y]中x和y不能超过length,i不大于 sum  
               for(int i=0;i<matrix.length;i++){          
                if(i<=sum && sum-i<matrix[i].length){  
                    list.add(matrix[i][sum-i]);
                }
            } 
        }
        int res[] = new int[list.size()];
        for(int i=0;i<list.size();i++){
            res[i] = list.get(i);
        }
        return res;
    }

我的输入:

[[1,2,3],[4,5,6],[7,8,9]]

我的输出:

[1,2,4,3,5,7,6,8,9]

思路

我是这么想的,既然是按照对角线遍历,那么每次遍历的次数多少呢?M+N-1次.

sum是通过观察得到的,代表坐标和,如果是M行N列的数组,即array.length等于M,array[0].length等于N,sum最大就是M+N-2.

比如题目中的数字9的坐标就可以理解为[2,2],因为是三行三列的数组,所以M+N等于6,减去2就是最右下角的元素的坐标和4.

好吧,是有点啰嗦.

第三步:调整遍历顺序

看图可知,偶数的时候从下往上遍历,奇数的时候从上往下遍历.

 public int[] findDiagonalOrder(int[][] matrix) {
        int res0[] = new int[0];
        if(matrix.length==0) return res0;
        List<Integer> list = new ArrayList(); 
        //定义sum为x,y的坐标之和,如果是3行5列,则最右下角的点的坐标和就是6
        for(int sum=0;sum<matrix.length+matrix[0].length-1;sum++){
            if(sum%2==1){                                   //如果sum为奇数,从上向下遍历
               for(int i=0;i<matrix.length;i++){          
                if(i<=sum && sum-i<matrix[i].length){  //判断条件是matrix[x][y]中x和y不能超过length,i不大于 sum  
                    list.add(matrix[i][sum-i]);
                }
            } 
            }else{                                           //如果sum为偶数,从下向上遍历
               for(int i=matrix.length-1;i>=0;i--){
                if(i<=sum && sum-i<matrix[i].length){
                    list.add(matrix[i][sum-i]);
                }
            }  
            }
            
        }
        int res[] = new int[list.size()];
        for(int i=0;i<list.size();i++){
            res[i] = list.get(i);
        }
        return res;
    }

我的输入:

[[1,2,3],[4,5,6],[7,8,9]]

我的输出:

[1,2,4,7,5,3,6,8,9]

完美输出结果,大功告成!

不要问我执行效率,我是不会告诉你们的!

咳咳,下面我们来看几个比较用时更少的解法.

其他解答

3ms范例

public int[] findDiagonalOrder(int[][] matrix) {
    if (matrix == null || matrix.length == 0) {
        return new int[]{};
    }
    int r = 0, c = 0;
    int row = matrix.length, col = matrix[0].length;
    int[] res = new int[row * col];
    for (int i = 0; i < res.length; i++) {
        res[i] = matrix[r][c];
        // r + c 即为遍历的层数,偶数向上遍历,奇数向下遍历
        if ((r + c) % 2 == 0) {
            if (c == col - 1) {
                // 往右移动一格准备向下遍历
                r++;
            } else if (r == 0) {
                // 往下移动一格准备向下遍历
                c++;
            } else {
                // 往上移动
                r--;
                c++;
            }
        } else {
            if (r == row - 1) {
                // 往右移动一格准备向上遍历
                c++;
            } else if (c == 0) {
                // 往上移动一格准备向上遍历
                r++;
            } else {
                // 往下移动
                r++;
                c--;
            }
        }
    }
    return res;
}

2ms范例

public int[] findDiagonalOrder(int[][] matrix) {  
        int leni=matrix.length;
        if(leni==0)
            return new int[0];
        int lenj=matrix[0].length;
        int[] ans = new int[leni*lenj];
        int k =0;
        int i=0,j=0;
        boolean sign = true;
        while(i>=0&&j<lenj&&i<leni&&j>=0){
            if(sign){
                while(i>=0&&j<lenj){
                    ans[k++] = matrix[i--][j++];
                }
                i++;
                j--;
                if(j+1<lenj)
                    j++;
                else
                    i++;
            }else{
                while(i<leni&&j>=0){
                    ans[k++]=matrix[i++][j--];
                }
                i--;
                j++;
                if(i+1<leni){
                    i++;
                }else
                    j++;
            }
            sign =!sign;
        }
        return ans;
    }

1ms范例

public int[] findDiagonalOrder(int[][] matrix) {
        if (matrix == null) return null;
        if (matrix.length == 0) return new int[0];
        int row = matrix.length, col = matrix[0].length;
        int[] result = new int[row * col];
        if (row == 1) return matrix[0];
        if (col == 1) {
            for (int i = 0; i < row; i++) {
                result[i] = matrix[i][0];
            }
            return result;
        }
        result[0] = matrix[0][0];
        result[result.length - 1] = matrix[row - 1][col - 1];
        int i = 0, j = 1, k = 1;
        while (k < result.length - 1) {
            while (i < row && j >= 0) {
                result[k++] = matrix[i++][j--];
            }
            if (i == row) {
                i = row - 1;
                j += 2;
            }
            else if (j < 0) j += 1;
            while (i >= 0 && j < col) {
                result[k++] = matrix[i--][j++];
            }
            if (j == col) {
                j = col - 1;
                i += 2;
            }
            else if (i < 0) i += 1;
        }
        return result;
    }

总结

虽然想出来的方法效率很低,但是能想出来这种解法与我而言已经是莫大的鼓舞了.

通过这个题我学会了如何去渐进式地思考,分步解决问题.而且我对二维数组的理解也加深了许多.

我是个刚开始接触算法的小白,文中有什么错误的地方希望大家可以给我指正,或者有什么好的学习算法的方式方法也可以在评论中留言或者私信发给我,谢谢各位大佬.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!