单选题
2-1 数组A[1..5,1..6]每个元素占5个单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,则元素A[5,5]的地址为:
A.1120 B.1125 C.1140 D.1145
解析 答案为C,
1000
A[1,1]...A[1,6] +6*5
A[2,1]...A[2,6] +6*5
A[3,1]...A[3,6] +6*5
A[4,1]...A[4,6] +6*5
A[5,1]...A[5,5] +5*5
1000 + (6*5)*4 + 5*5 = 1000 + 120 + 25 = 1145
但是1145是A[5,5]之后的内存单元的地址(也就是A[5,6]的首地址)。因此A[5,5]的首地址是1145-5=1140。
2-5 有一个100阶的三对角矩阵(M),其三对角元素(m_{i,j})(1≤(i)≤100,1≤(j)≤100)按行优先次序压缩存入下标从0开始的一维数组(N)中。元素(m_{30,30})在(N)中的下标是:
A.86 B.87 C.88 D.89
解析 答案为B,解答此题的关键在于什么是三对角矩阵(来源:三对角矩阵压缩),如下图所示:
除了第一行和最后一行是每行2个元素外,中间的每行都是三个元素。
因此,答案显而易见,(m_{30,30})编号就是2+3*28+2 -1= 87;
2-6 设有一个 12×12 的对称矩阵(M),将其上三角部分的元素(m_{i,j})(1≤(i)≤(j)≤12)按行优先存入C语言的一维数组(N)中,元素(m_{6,6})在(N)中的下标是:
A.50 B.51 C.55 D.66
解析 答案为A,上三角矩阵从第一行开始元素数量依次是:12,11,10,9,8,7,6,5,4,3,2,1,m6,6表示上三角区域的第6行第1个,所以m6,6为第51个元素,占数组位置为a[50]。
函数题 数组元素的区间删除
给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素。删除后表中剩余元素保持顺序存储,并且相对位置不能改变。
函数接口定义:
int Delete( int A[], int L, int minA, int maxA );
其中
A
是整型数组,存储原始线性表的元素;L
是表长,即A
中元素的个数;minA
和maxA
分别为待删除元素的值域的下、上界。函数Delete
应将A
中所有值大于minA
而且小于maxA
的元素删除,同时保证表中剩余元素保持顺序存储,并且相对位置不变,最后返回删除后的表长。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 20
int Delete( int A[], int L, int minA, int maxA );
int main()
{
int A[MAXN], L, minA, maxA, i;
scanf("%d", &L);
for (i=0; i<L; i++) scanf("%d", &A[i]);
scanf("%d %d", &minA, &maxA);
L = Delete(A, L, minA, maxA);
for (i=0; i<L; i++) printf("%d ", A[i]);
printf("
");
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
10
4 -8 2 12 1 5 9 3 3 10
0 4
输出样例:
4 -8 12 5 9 10
Time Limit Exceeded
一开始的时候,觉得这题很简单,直接的思路就是,从0到L-1遍历,每当找到符合题目要求的A[i]是进行删除操作,即运用一个for循环,让i+1到L-1的数组元素提前(特别注意一下,提前完之后,在把L减1的同时,i也需要减去1,因为此时的A[i]是原来的A[i+1]。具体代码如下:
int Delete( int A[], int L, int minA, int maxA ){ for(int i=0;i<L;i++){ if(A[i]>minA&&A[i]<maxA) { for(int j=i;j<L-1;j++) A[j]=A[j+1]; L--; i--; //此时A[i]的值发生改变,需重新判断 } } return L; }
显而易见,其时间复杂度为(O(n^{2})),不够效率,并且提交上去也有一个点超时。因此只能改变解题思路了。
Accepted
第二种做法,我们通过第一种做法进行改进。我们发现,在第一种做法中,我们每遇到一个符合题意的数组元素就要从它到数组末尾进行一次遍历删除,这样使程序一直在做重复的事,那么有没有办法可以减少一遍遍重复做删去的事呢?我想到的是,我将不需要被删去的数组元素存到一个新的数组里,定义一个变量k来记录这个数组里元素的个数,并在最后将这个数组里的元素赋值给原数组,同时返回k值,这样做法我们会发现时间复杂度变为了(O(n)),使程序变得高效了许多。代码如下:
int Delete( int A[], int L, int minA, int maxA ){ int B[MAXN],k=0; for(int i=0;i<L;i++) if(A[i]<=minA||A[i]>=maxA) B[k++]=A[i]; for(int i=0;i<k;i++) A[i]=B[i]; return k; }
编程题 数组元素的区间删除
给定一个顺序存储的线性表,请设计一个算法查找该线性表中最长的连续递增子序列。例如,(1,9,2,5,7,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)。
输入格式:
输入第1行给出正整数n(≤105);第2行给出n个整数,其间以空格分隔。
输出格式:
在一行中输出第一次出现的最长连续递增子序列,数字之间用空格分隔,序列结尾不能有多余空格。
输入样例:
15
1 9 2 5 7 3 4 6 8 0 11 15 17 17 10
输出样例:
3 4 6 8
Accepted
这一题,我就采用了(O(n))的算法,通过一次遍历,找出第一次出现的最长连续递增子序列,当然,可能还会有些地方写的不够简便,也同时希望大家可以提供更多好的意见来相互交流学习。
#include <iostream> using namespace std; int main() { int n,a[100000]; int max=0; int num=1; int left=0,right=0; int L=0,R=0; cin >> n; for(int i=0;i<n;i++) cin >> a[i]; for(int i=1;i<n;i++){ if(a[i]>a[i-1]){ right=i; num++; } else{ if(num>max){ L=left; R=right; max=num; } right=i; left=i; num=1; } } if(num>max){ L=left; R=right; } for(int i=L;i<=R;i++){ cout << a[i] ; if(i!=R) cout <<" "; else cout << endl; } return 0; }