1.题目描述
回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。
输入
输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。
输出
输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。
样例输入
3 3
1 2 3
4 5 6
7 8 9
样例输出
1 4 7 8 9 6 3 2 5
2.思路
取数方向相当于 下–>右–>上–>左
所以可以编写四个方向的函数(down,right,up,left)对此进行操作,再写一个总的方法(take)来调用四个子方法,每次需要判断到底是哪个方向上的坐标不变,将输出过的那个坐标上的数改为0,我们就能知道它已经被遍历过了。
但是最后提交时还是不对,73分,看测试数据的时候他也没给我到底哪不对,所以暂时还没真正的做出来,也不知道到底哪错了,希望有热心大佬指出一下
代码:
import java.util.Scanner;
public class ReturnShapeTaking {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int[][] m = new int[a][b];
for(int i = 0; i < a; ++i) {
for(int j = 0; j < b; ++j) {
m[i][j] = sc.nextInt();
}
}
take(m,a,b);
}
private static void take(int[][] m, int a, int b) {
//相当于逆时针取数:下--》右--》上--》左
//判断a,b大小,防止行列大小不同时,出现数组下标越界异常
if(a >= b) {
for(int j = 0; j < b; ++j) {
down(m,j);
right(m,a - j - 1);
up(m,b - j - 1);
left(m,j);
}
} else if(a <= b) {
for(int j = 0; j < a; ++j) {
down(m,j);
right(m,a - j - 1);
up(m,b - j - 1);
left(m,j);
}
}
}
public static void down(int[][] m, int j) {//列不变,行在变
for(int i = 0; i < m.length; ++i) {
if(m[i][j] != 0) {
System.out.print(m[i][j] + " ");
m[i][j] = 0;
}
}
}
public static void right(int[][] m, int i) {//行不变,列在变
for(int j = 0; j < m[0].length ; ++j) {
if(m[i][j] != 0) {
System.out.print(m[i][j] + " ");
m[i][j] = 0;
}
}
}
public static void up(int[][] m, int j) {//列不变,行在变
for(int i = m.length - 1; i >= 0; --i) {
if(m[i][j] != 0) {
System.out.print(m[i][j] + " ");
m[i][j] = 0;
}
}
}
public static void left(int[][] m, int i) {//行不变,列在变
for(int j = m[i].length - 1; j >=0; --j) {
if(m[i][j] != 0) {
System.out.print(m[i][j] + " ");
m[i][j] = 0;
}
}
}
}
另外,需要注意的是
System.out.println("*****"+m[0].length);//表示m[0]这列的长度
System.out.println("======"+m.length);//表示行的长度,之前忽视了这个问题
3.正确解法
然后老规矩,搜大佬写的来看
链接:link转载解法.
思路:(转载上文)
1.首先,每一轮开始的坐标x,y都相同,开始为0,后续每轮加一。我们发现循环打印的条件是columns>startX2&&rows>startY2.
2.打印可能有四步,向右,向下,向左,向上。但并不是每次都如此,因此我们要分析具体条件。(1)第一步向右总是需要的(2)当终止行号大于起始行号,也就是至少要两行,才有第二步向下。(3)至少有两行之后,还要至少两列才有第三步向左。(4)有两列的情况下,当至少有三行才有第四步向上。
这个已经说得很清楚了,然后自己再debug几个示例。后面自己敲了一遍,改成了这道题的要求,原文输出顺序略有差异。
import java.util.Scanner;
public class ReturnShapeTaking_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int[][] m = new int[a][b];
for(int i = 0; i < a; ++i) {
for(int j = 0; j < b; ++j) {
m[i][j] = sc.nextInt();
}
}
sc.close();
take(m,a,b);
}
private static void take(int[][] m, int a, int b) {
if (m==null||a<=0||b<=0)
return;
int start = 0;
while(a > start * 2 && b > start * 2) {
//start一次打印结束后,start需要后移,如果行列有一个小于start*2就意味着已经打印完了,
//因为一次循环打印可以处理两行两列。这个控制个人感觉还是特别巧妙,做题的时候想不到
printNum(m,a,b,start);
start++;
}
}
private static void printNum(int[][] m, int a, int b, int start) {
int endX = a - start - 1;//x横坐标与行有关
int endY = b - start - 1;
//第一次必须向下打印(因为会出现最后只剩一列的时候)
for(int i = start; i <= endX; ++i) {
System.out.print(m[i][start] + " ");
}
//向右打印,但是要判断是否还需要向右打印
if(start < endY) {
for(int i = start + 1; i <= endY; ++i) {
System.out.print(m[endX][i] + " ");
}
}
//向上打印,但是要判断是否还需要向上打印
if(start < endX && start < endY) {
for(int i = endX - 1; i >= start; --i) {
System.out.print(m[i][endY] + " ");
}
}
//向左打印,但是要判断是否还需要向左打印
if(start < endY && start < endX) {
for(int i = endY - 1; i > start; --i) {
System.out.print(m[start][i] + " ");
}
}
}
}
自己有些细节没把握好,打印的数到底和横纵坐标哪个有关,打印循环的条件是大于start而不是大于0,等……背着写一遍之后找错找安逸了。。。。。疯狂举例debug
学习心得:应该是二维数组这块的基础没有打牢,把自己绕晕了,真惨。一页多的提交记录。