目录
刷题日期:
个人刷题记录,代码收集,来源皆为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;
}
}
总结
以上就是本题的内容和学习过程了,这题一点也不简单,要判断的条件不好理清,边界也得设置的足够巧妙,还得利用代码自身的一些特性,基础仍然需要进步啊。
欢迎讨论,共同进步。