题目描述:
给定一个 m行、n 列的矩阵,请按照顺时针螺旋的顺序输出矩阵中所有的元素(从[0][0]位置开始,具体请参见下图)。
输入格式:
每次程序运行时,首先在第一行输入 22 个整数,分别对应题目描述中的 m 和 n(1≤m,n≤100),之间用一个空格分隔。接下来输入 m 行,每行包含 n 个整数(取值范围:[-10000,10000]),每两个整数之间用一个空格分隔。
输出格式:
输出为一行,包括 m×n 个整数,按照题目要求的顺序依次输出所有矩阵元素,任意两个整数之间用一个空格分隔,最后一个整数后面没有空格。
输入示例:
7 10
18 31 29 6 16 74 60 83 31 86
64 39 9 87 24 31 43 23 23 93
56 78 32 50 75 86 78 78 49 99
6 57 15 90 58 99 19 88 45 62
39 29 35 3 82 87 39 5 95 71
29 78 34 83 19 17 21 94 7 28
66 87 66 58 52 3 55 95 38 76
输出示例:
18 31 29 6 16 74 60 83 31 86 93 99 62 71 28 76 38 95 55 3 52 58 66 87 66 29 39 6 56 64 39 9 87 24 31 43 23 23 49 45 95 7 94 21 17 19 83 34 78 29 57 78 32 50 75 86 78 78 88 5 39 87 82 3 35 15 90 58 99 19
思路分析:
看到这个题目的时候,我产生了两个想法:
一个是在输入的时候直接按照输出的顺序储存数据,优点是输出简单,遍历一维数组即可;缺点是输入复杂;限制条件是输入的时候因为是从stdin获取,好像无法随机读取,文件或许可以实现。
所以我选择了第二种:输入简单,输出麻烦一些。就是输入的时候正常输入,输出的时候按照要求的顺序。
我的解法:
灵感来源:蚕吃桑叶。
定义一只虫子worm,
有触须cirrus,负责搜寻数据寻找方向;有头head,负责“吃”(输出数据,并把经过的数据清零);有尾巴tail,辅助辨别身体的朝向(点是没有方向的,所以只有head不行)。
因为题目要求顺时针,这个问题可以简化很多。只需要判断前方和右边(虫子身体的右边)是否有数据即可。
虫子移动的距离用循环控制,定义一个计数变量,每“吃掉”一个数据,计数变量加一,当"吃掉"(m * n)个数据之后停止。
输出数据后清零原因;即防止重复输出数据,也避免了判断边界的麻烦(所以定义的矩阵MAX == 102);
代码实现:
#include <stdio.h>
#include <string.h>
#define MAX 102
typedef struct Worm{
int *cirrus;
int *head;
int *tail;
}Worm;
Worm worm = {0};
void Scan (int matrix[MAX][MAX], int row, int col);
void Eat (void);
int Sniff (void);
void Right (void);
void Down (void);
void Left (void);
void Up (void);
void Move (int key);
void Print (int matrix[MAX][MAX], int row, int col);
int main() {
int matrix[MAX][MAX];
int row;
int col;
memset (matrix, 0, sizeof(matrix));
scanf ("%d %d\n", &row, &col);
Scan (matrix, row, col);
Print (matrix, row, col);
return 0;
}
void Scan (int matrix[MAX][MAX], int row, int col) {
int counter1, counter2;
for (counter1 = 1; counter1 <= row; counter1++) {
for (counter2 = 1; counter2 <= col; counter2++) {
scanf ("%d", &(matrix[counter1][counter2]));
getchar();
}
}
}
void Right (void) {
worm.tail = worm.head;
worm.head++;
}
void Down (void) {
worm.tail = worm.head;
worm.head += MAX;
}
void Left (void) {
worm.tail = worm.head;
worm.head--;
}
void Up (void) {
worm.tail = worm.head;
worm.head -= MAX;
}
void Move (int key) {
if (key == 6) {
Right();
return ;
}
if (key == 4) {
Left();
return;
}
if (key == 8) {
Up();
return;
}
if (key == 2) {
Down();
return;
}
}
void Eat (void) {
printf("%d", *(worm.head));
*(worm.head) = 0;
}
int Sniff (void) {
if (worm.head - worm.tail == 1) {//身体向右
if (*(worm.cirrus = worm.head + 1) != 0) {//右
return 6;
} else if (*(worm.cirrus = worm.head + MAX) != 0) {//下
return 2;
}
}
if (worm.head - worm.tail == MAX) {//身体向下
if (*(worm.cirrus = worm.head + MAX) != 0) {//下
return 2;
} else if (*(worm.cirrus = worm.head - 1) != 0) {//左
return 4;
}
}
if (worm.head - worm.tail == -1) {//身体向左
if (*(worm.cirrus = worm.head - 1) != 0) {//左
return 4;
} else if (*(worm.cirrus = worm.head - MAX) != 0) {//上
return 8;
}
}
if (worm.head - worm.tail == -MAX) {//身体向上
if (*(worm.cirrus = worm.head - MAX) != 0) {//上
return 8;
} else if (*(worm.cirrus = worm.head + 1) != 0) {//右
return 6;
}
}
}
void Print (int matrix[MAX][MAX], int row, int col) {
int counter;
worm.head = &matrix[1][0];
worm.tail = worm.head - 1;
for (counter = 1; counter <= row * col; counter++) {
Move(Sniff());//寻找数据并向数据移动
Eat();//输出元素后清零
counter != row * col && putchar(' ');
}
}
/*
7 10
18 31 29 6 16 74 60 83 31 86
64 39 9 87 24 31 43 23 23 93
56 78 32 50 75 86 78 78 49 99
6 57 15 90 58 99 19 88 45 62
39 29 35 3 82 87 39 5 95 71
29 78 34 83 19 17 21 94 7 28
66 87 66 58 52 3 55 95 38 76
18 31 29 6 16 74 60 83 31 86 93 99 62 71 28 76 38 95 55 3 52 58 66 87 66 29 39 6 56 64 39 9 87 24 31 43 23 23 49 45 95 7 94 21 17 19 83 34 78 29 57 78 32 50 75 86 78 78 88 5 39 87 82 3 35 15 90 58 99 19
*/
时间复杂度:O(n);
空间复杂度:O(1);
题目来源:
开课吧
https://xue.kaikeba.com/interactive-course/11779
(我是从这里知道的)
类似题目:
Leetcode:
https://leetcode.com/problems/spiral-matrix/description/
一些废话:
菜鸟一只,互相交流,共同成长。