今年五一因为疫情的原因,回不去。只好刷下题目。
以下是牛客网考研机试中的一个题目。
题目要求找出每列中最大的两个数,然后输出的时候要求保留原矩阵的排列顺序。换句话说,输出的时候要根据矩阵的顺序进行,而不是固定将最大和次大的依此输出。否则是通不过的。
二维数组实现方法
使用二维数组来实现最容易和直接想到的,程序运行速度较快但是占用的内存会多一些。
简单说下思路:
- 定义1个20个元素的数组d
- 定义2个二维数组e和f,其中e中存储最大值,而f中储存次大值。其中e的第2个维度存储其对应的行数。
- 依此读取输入的每个值,如果其值大于最大值,则将次大值中的更新为最大值的值。之后再将最大值进行更新。
代码实现
下面是对应的代码:
#include <stdio.h>
int main(int argc, char *argv[]) {
int c;
while (scanf("%d", &c) != EOF) {
int d[20] = {0};
int e[5][2] = {0};
int f[5][2] = {0};
d[0] = c;
for (int i = 1; i < 20; ++i) {
scanf("%d", &c);
d[i] = c;
}
int num = 0;
//每1列
for (int j = 0; j < 5; ++j) {
for (int i = 0; i < 4; ++i) {
c = d[j + i * 5];
if (c > e[num][0]) {
//次大值更新
f[num][0] = e[num][0];
//最大值更新
e[num][0] = c;
//更新最大值的行数
e[num][1] = i;
} else if (c > f[num][0] && f[num][0] < e[num][0]) {
//更新次大值
f[num][0] = c;
//更新次大值的行数
f[num][1] = i;
}
}
num++;
}
//输出每行顺序最小的行
for (int k = 0; k < 4; ++k) {
if (e[k][1] < f[k][1]) {
printf("%d ", e[k][0]);
} else {
printf("%d ", f[k][0]);
}
}
if (e[4][1] < f[4][1]){
printf("%d\n", e[4][0]);
}else{
printf("%d\n", f[4][0]);
}
//输出每行顺序最小的行
for (int k = 0; k < 4; ++k) {
if (e[k][1] > f[k][1]) {
printf("%d ", e[k][0]);
} else {
printf("%d ", f[k][0]);
}
}
if (e[4][1] > f[4][1]){
printf("%d\n", e[4][0]);
}else{
printf("%d\n", f[4][0]);
}
}
return 0;
}
最后是通过后的结果:
由于代码写得比较繁琐,因此占用的内存比较多。
下面再分享一种更为逻辑更为简单的方法。
一维数组实现方法
首先我们定义1个只有10个元素的数组e
,用于存储相应输出的结果。而定义1个20个元素的数组d
来存储输入的每个结果。
想法就是让每组前2个元素存储的是最大和次大的值。当输入1个值时,我们将其与每组的最大和次大值进行比较。因为假定此时的大小顺序已经确定。
此时会出现4种情况,我们使用表格的形式进行说明,使用a表示每组第1个值,而b表示每组第2个值,而c表示输入的值:
a | b | 说明 |
---|---|---|
c > a | c > b | c为最大值 |
c > a | c < b | c为次大值 |
c < a | c > b | c为次大值 |
c < a | c < b | 舍弃,c不是最大值和最小值 |
情况1
对于情况1,可以看到当c > a
且c > b
时,说明此时c为最大值。那么此时该组的次大值是哪个呢?此时不妨让a
和b
再比较一次。如果a > b
,那么说明a
是次大值,此时直接让c
替换b
上的值即可。因为此时c
的顺序是在a
和b
之后的。
但是,如果b > a
,说明此时b
是次大值。那么我们就需要将次大值b
往前移动1位替换掉a
,再将c
替换b
原来的值。
情况2
对于情况2,此时c > a
但c < b
,说明c
此时是次大值,而b
是最大值。此时b
的顺序在后面,按照大小顺序,需要进行相应的移位操作。只要将b
往前移动1位替换掉原有的次大值a
,再将c
的值写入即可。
情况3
对于情况3,此时c < a
但c > b
,说明c
此时仍然是次大值,但是当前情况a
是最大值。由于a
的顺序在前面,此时就不需要进行任何的移位操作,直接将c
的值覆盖原有次大值b
的值即可。
情况4
对于情况4,此时c
比a
和b
都小,这说明c
不是最大值和次大值,直接将其舍弃即可。
代码实现
说完以上的思路,下面是对应实现的代码:
#include <stdio.h>
int main(int argc, char *argv[]) {
int c;
while (scanf("%d", &c) != EOF) {
int d[20] = {0};
int e[10] = {0};
int prev, next;
d[0] = c;
for (int i = 1; i < 20; ++i) {
scanf("%d", &c);
d[i] = c;
}
for (int j = 0; j < 5; ++j) {
prev = j * 2;
next = j * 2 + 1;
for (int i = 0; i < 4; ++i) {
c = d[j + i * 5];
if (c >= e[prev] && c >= e[next]) {
//c为最大值
if (e[prev] >= e[next]) {
//e[prev]为次大值
e[next] = c;
} else {
//e[next]为次大值
e[prev] = e[next];
e[next] = c;
}
} else if (c >= e[prev] && c <= e[next]) {
//c为次大值
e[prev] = e[next];
e[next] = c;
} else if (c <= e[prev] && c >= e[next]) {
//c为次大值
e[next] = c;
}
}
}
for (int k = 0; k < 2; ++k) {
for (int i = 0; i < 4; ++i) {
printf("%d ", e[i * 2 + k]);
}
printf("%d\n", e[4 * 2 + k]);
}
}
return 0;
}
最后就是输出的问题,此时先按奇数顺序输出,再按偶数顺序输出即可得到最终的答案。因为我们默认假定每组第1个元素是最大值,而每组第2个元素是次大值。而在这个过程中,值会根据实际的情况发生变动,但是其顺序已经在运行的过程中被固定了。
下面是通过后的结果:
可以看到运行的时间比之前使用二维数组的时间还要长一些。但是占用的内存大小却小了很多。