【剑指Offer】个人学习笔记_29_顺时针打印矩阵

刷题日期:

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

剑指 Offer 29. 顺时针打印矩阵

难度简单221

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

示例 1:

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

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

限制:

  • 0 <= matrix.length <= 100
  • 0 <= matrix[i].length <= 100
题目分析

主要问题在于如何判断是否到了矩阵的角落,如何进入更里面的圈,定位坐标。

在矩阵内顺时针绕圈,也就是遇到角落就转向,横坐标加,纵坐标加,横坐标减,纵坐标减,每转换一次范围就小一圈,并且可以建立一个bool矩阵判断是否已经经过了,绕到已经经过的就退出。

这题一点都不简单……

初始解答:

尝试一般的迭代解法,

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        //首先获取矩阵的长宽
        if (matrix == null) return null; //特殊情况
        if ( matrix.size() == 1 && n = matrix[0].size() == 1) return matrix;
        int x = 0, y = 0, m = matrix.size(), n = matrix[0].size();
        int[] result = new int[m*n-1];
        for (int i = 0; i < m * n; i++) {

        }
        return result;
    }
}

写不出来,参考方法一。

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        //首先获取矩阵的长宽
        int row = matrix.length; //行
        if (row == 0) return new int[0]; //特殊情况
        int col = matrix[0].length; //列
        int[] res = new int[row*col];
        int idx = 0, left = 0, top = 0, right = col - 1, bottom = row - 1; //边界
        while (true) {//主循环
            //往右
            for (int i = left; i <= right; i++) res[idx++] = matrix[top][i];
            if (++top > bottom) break;

            //往下
            for (int i = top; i <= bottom; i++) res[idx++] = matrix[i][right];
            if (--right < left) break;

            //往左
            for (int i = right; i >= left; i--) res[idx++] = matrix[bottom][i];
            if (--bottom < top) break;

            //往上
            for (int i = bottom; i >= top; i--) res[idx++] = matrix[i][left];
            if (++left > right) break;

        }
        return res;
    }
}

执行结果: 通过

显示详情

执行用时:1 ms, 在所有 Java 提交中击败了97.52%的用户

内存消耗:40.1 MB, 在所有 Java 提交中击败了6.08%的用户

学习K神更简便的写法

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0) return new int[0]; //特殊情况
        int x = 0, l = 0, t = 0, r = matrix[0].length - 1, b = matrix.length - 1; //边界
        int[] res = new int[(r + 1) * (b + 1)];
        while (true) {//主循环
            //往右
            for (int i = l; i <= r; i++) res[x++] = matrix[t][i];
            if (++t > b) break;

            //往下
            for (int i = t; i <= b; i++) res[x++] = matrix[i][r];
            if (--r < l) break;

            //往左
            for (int i = r; i >= l; i--) res[x++] = matrix[b][i];
            if (--b < t) break;

            //往上
            for (int i = b; i >= t; i--) res[x++] = matrix[i][l];
            if (++l > r) break;

        }
        return res;
    }
}

其实只是名字变短了,代码量没有变。

参考方法二,但是最后一位总是零,寻找问题

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0) return new int[0]; //特殊情况
        int x = 0, l = 0, t = 0, r = matrix[0].length - 1, b = matrix.length - 1; //边界
        int[] res = new int[(r + 1) * (b + 1)];
        while (x < (r + 1) * (b + 1)) {//用数组长度来判断结束
            //往右
            for (int i = l; i <= r; i++) res[x++] = matrix[t][i];
            t++;

            //往下
            for (int i = t; i <= b; i++) res[x++] = matrix[i][r];
            r--;

            //往左
            for (int i = r; i >= l && t <= b; i--) res[x++] = matrix[b][i];
            b--;

            //往上
            for (int i = b; i >= t && l <= r; i--) res[x++] = matrix[i][l];
            l++;
        }
        return res;
    }
}

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

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

差别

预期结果 [1,2,3,6,9,8,7,4,5]

替换前面的条件,替换while循环条件,替换循环内的条件,都缺一个数,但是方法二就没有问题?

最后找到了原因,就是循环的判断,别人用的都是row、col或true,我上面的代码直接用r、b,在循环内部已经改变了边界值,所以导致出错,还是自己太粗心了。

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0) return new int[0]; //特殊情况
        int x = 0, l = 0, t = 0, r = matrix[0].length - 1, b = matrix.length - 1; //边界
        int[] res = new int[(r + 1) * (b + 1)];
        int row = matrix.length,col = matrix[0].length;
        while (x < col * row) { //用行和列乘就可以
        // while (x < (r + 1) * (b + 1)) {//这里不行的原因是在循环里把r、b已经改变了,所以出错,就没有人这样用的,是自己太粗心了
            //往右
            for (int i = l; i <= r; i++) res[x++] = matrix[t][i];
            t++;

            //往下
            for (int i = t; i <= b; i++) res[x++] = matrix[i][r];
            r--;

            //往左
            for (int i = r; i >= l && t <= b; i--) res[x++] = matrix[b][i];
            b--;

            //往上
            for (int i = b; i >= t && l <= r; i--) res[x++] = matrix[i][l];
            l++;
        }
        return res;
    }
}

执行结果:通过 效果也更好了。

显示详情

执行用时:1 ms, 在所有 Java 提交中击败了97.52%的用户

内存消耗:39.7 MB, 在所有 Java 提交中击败了71.89%的用户

学习他人:

方法一:

Sumail🍒L2 2020-06-04

public class Solution {
    public int[] spiralOrder(int[][] matrix) {
        int row = matrix.length;
        if (row == 0) {
            return new int[0];
        }
        int col = matrix[0].length;
        int[] res = new int[row * col];
        int idx = 0;
        int left = 0, top = 0, right = col - 1, bottom = row - 1;
        while (true) {
            //从左往右走
            for (int i = left; i <= right; i++) {
                res[idx++] = matrix[top][i];
            }
            if (++top > bottom) {
                break;
            }
            //从上往下走
            for (int i = top; i <= bottom; i++) {
                res[idx++] = matrix[i][right];
            }
            if (--right < left) {
                break;
            }
            //从右往左走
            for (int i = right; i >= left; i--) {
                res[idx++] = matrix[bottom][i];
            }
            if (--bottom < top) {
                break;
            }
            //从下往上走
            for (int i = bottom; i >= top; i--) {
                res[idx++] = matrix[i][left];
            }
            if (++left > right) {
                break;
            }
        }
        return res;
    }
}

方法二:

坏森生L1 2020-10-28

你说面试考这题的得夺笋啊

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0)
            return new int[0];
        int row = matrix.length,col = matrix[0].length;
        int[] ans = new int[row * col];
        int k = 0;
        int l =0,r = col -1,t =0,b = row -1;
        while(k < col * row){
            for(int i=l;i<=r;i++)
                ans[k++] = matrix[t][i];
            t++;
            for(int i=t;i<=b;i++)
                ans[k++] = matrix[i][r];
            r--;
            for(int i=r;i>=l && t <= b;i--)
                ans[k++] = matrix[b][i];
            b--;
            for(int i=b;i>=t && l <= r;i--)
                ans[k++] = matrix[i][l];
            l++;
        }
        return ans;
    }
}

方法三:

appleL1 2021-03-20

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0)return new int[0];
        int m = matrix.length, n = matrix[0].length;
        int[] res = new int[m * n];
        int t = 0;
        for(int i = 0; i < (Math.min(m, n) + 1) / 2; i++){
            for(int j = i; j < n - i; j++){
                res[t++] = matrix[i][j];
            }
            for(int j = i + 1; j < m - i; j++){
                res[t++] = matrix[j][n - i - 1];
            }
            for(int j = n - i - 2; j >= i && m - i - 1 > i; j--){
                res[t++] = matrix[m - i - 1][j];
            }
            for(int j = m - i - 2; j >= i + 1 && n - i - 1 > i; j--){
                res[t++] = matrix[j][i];
            }
        }
        return res;
    }
}

方法四:

K神 Java 代码利用了 ++ 操作的便利性,详情可见 ++i 和 i++ 的区别 ;

res[x++] 等价于先给 res[x] 赋值,再给 x 自增 11 ;

++t > b 等价于先给 t 自增 11 ,再判断 t > b 逻辑表达式。

作者:jyd
链接:https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/solution/mian-shi-ti-29-shun-shi-zhen-da-yin-ju-zhen-she-di/
来源:力扣(LeetCode)

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0) return new int[0];
        int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
        int[] res = new int[(r + 1) * (b + 1)];
        while(true) {
            for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
            if(++t > b) break;
            for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
            if(l > --r) break;
            for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
            if(t > --b) break;
            for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
            if(++l > r) break;
        }
        return res;
    }
}

总结

以上就是本题的内容和学习过程了,这题一点也不简单,要判断的条件不好理清,边界也得设置的足够巧妙,还得利用代码自身的一些特性,基础仍然需要进步啊。

欢迎讨论,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值