文章目录
- PTA--基础编程题目集
- 1、简单输出整数
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 2、多项式求和
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 3、简单求和
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 4、求自定类型元素的平均
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 5、求自定类型元素的最大值
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 6、求单链表结点的阶乘
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 7、统计某类完全平方数
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 8、简单阶乘计算
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 9、统计各位数字
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 10、阶乘计算升级版(▲)
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 11、求自定类型元素序列的中位数
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 题解:
- 12、判断奇偶性
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例1:
- 输出样例1:
- 输入样例2:
- 输出样例2:
- 题解:
- 13、折半查找
- 函数接口定义:
- 裁判测试程序样例:
- 输入样例:
- 输出样例:
- 输入样例:
- 输出样例:
- 题解:
- 14、总结
PTA–基础编程题目集
1、简单输出整数
本题要求实现一个函数,对给定的正整数N
,打印从1到N
的全部正整数。
函数接口定义:
void PrintN ( int N );
其中N
是用户传入的参数。该函数必须将从1到N
的全部正整数顺序打印出来,每个数字占1行。
裁判测试程序样例:
#include <stdio.h>
void PrintN ( int N );
int main ()
{
int N;
scanf("%d", &N);
PrintN( N );
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
输出样例:
1
2
3
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
题解:
这个题倒是没什么难度,只要注意输出符合格式样例即可。
/* 你的代码将被嵌在这里 */
void PrintN(int N){
for(int i = 0;i < N; i++){
printf("%d\n",i+1);
}
}
2、多项式求和
本题要求实现一个函数,计算阶数为n
,系数为a[0]
… a[n]
的多项式f(x)=∑i=0n(a[i]×x**i) 在x
点的值。
函数接口定义:
double f( int n, double a[], double x );
其中n
是多项式的阶数,a[]
中存储系数,x
是给定点。函数须返回多项式f(x)
的值。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
double f( int n, double a[], double x );
int main()
{
int n, i;
double a[MAXN], x;
scanf("%d %lf", &n, &x);
for ( i=0; i<=n; i++ )
scanf("%lf", &a[i]);
printf("%.1f\n", f(n, a, x));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
2 1.1
1 2.5 -38.7
输出样例:
-43.1
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
题解:
首先要看懂多项式的式子,这是一个求和公式:
f(x) = a[0]*(x^0) + a[1]*(x^1) + a[2]*(x^2) + ... + a[n]*(x^n)
提供两种解题方法:
1、引入<math.h>
//引入<math.h>,可以使用pow()
/*
* pow(i, j)表示i的j次幂,即i^j,如
* pow(2, 3) = 2^3 = 8
* pow(3, 2) = 3^2 = 9
*/
double f(int n, double a[], double x) {
double res = 0;
//遍历系数数组,累加a[i] * (x^i)
for (int i = 0; i <= n; i++) {
res += a[i] * pow(x, i);
}
return res;
}
2、不引入<math.h>
//不引入<math.h>
double f(int n, double a[], double x) {
double res = 0.0;
double x0 = 1.0; //x的零次方等于1
for (int i = 0; i <= n; ++i) {
if (a[i] != 0) {
res += a[i] * x0;
}
//后面的每次循环,x的幂加1
x0 *= x;
}
return res;
}
3、简单求和
本题要求实现一个函数,求给定的N
个整数的和。
函数接口定义:
int Sum ( int List[], int N );
其中给定整数存放在数组List[]
中,正整数N
是数组元素个数。该函数须返回N
个List[]
元素的和。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
int Sum ( int List[], int N );
int main ()
{
int List[MAXN], N, i;
scanf("%d", &N);
for ( i=0; i<N; i++ )
scanf("%d", &List[i]);
printf("%d\n", Sum(List, N));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
12 34 -5
输出样例:
41
题解:
遍历数组累加求和即可。
int Sum(int List[], int N) {
int sum = 0;
for (int i = 0; i < N; ++i) {
sum += List[i];
}
return sum;
}
4、求自定类型元素的平均
本题要求实现一个函数,求N
个集合元素S[]
的平均值,其中集合元素的类型为自定义的ElementType
。
函数接口定义:
ElementType Average( ElementType S[], int N );
其中给定集合元素存放在数组S[]
中,正整数N
是数组元素个数。该函数须返回N
个S[]
元素的平均值,其值也必须是ElementType
类型。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
typedef float ElementType;
ElementType Average( ElementType S[], int N );
int main ()
{
ElementType S[MAXN];
int N, i;
scanf("%d", &N);
for ( i=0; i<N; i++ )
scanf("%f", &S[i]);
printf("%.2f\n", Average(S, N));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
12.3 34 -5
输出样例:
13.77
题解:
//此题其实不难,遍历数组累加后除以总数N即可
//typedef float ElementType;相当于给float取了个别名而已
ElementType Average(ElementType S[], int N) {
double sum = 0;
for (int i = 0; i < N; ++i) {
sum += S[i];
}
return sum / N;
}
5、求自定类型元素的最大值
本题要求实现一个函数,求N
个集合元素S[]
中的最大值,其中集合元素的类型为自定义的ElementType
。
函数接口定义:
ElementType Max( ElementType S[], int N );
其中给定集合元素存放在数组S[]
中,正整数N
是数组元素个数。该函数须返回N
个S[]
元素中的最大值,其值也必须是ElementType
类型。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
typedef float ElementType;
ElementType Max( ElementType S[], int N );
int main ()
{
ElementType S[MAXN];
int N, i;
scanf("%d", &N);
for ( i=0; i<N; i++ )
scanf("%f", &S[i]);
printf("%.2f\n", Max(S, N));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
12.3 34 -5
输出样例:
34.00
题解:
//此题难度不大,只需要遍历数组找出最大值即可
ElementType Max(ElementType S[], int N) {
//假设s[0]最大
double max = S[0];
for (int i = 1; i < N; ++i) {
//如果s[i]>max,则max为s[i]
if (max < S[i]) {
max = S[i];
}
}
return max;
}
6、求单链表结点的阶乘
本题要求实现一个函数,求单链表L
结点的阶乘和。这里默认所有结点的值非负,且题目保证结果在int
范围内。
函数接口定义:
int FactorialSum( List L );
其中单链表List
的定义如下:
typedef struct Node *PtrToNode;
struct Node {
int Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node *PtrToNode;
struct Node {
int Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
int FactorialSum( List L );
int main()
{
int N, i;
List L, p;
scanf("%d", &N);
L = NULL;
for ( i=0; i<N; i++ ) {
p = (List)malloc(sizeof(struct Node));
scanf("%d", &p->Data);
p->Next = L; L = p;
}
printf("%d\n", FactorialSum(L));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
5 3 6
输出样例:
846
题解:
本次难度不大,只需要遍历链表即可,求出每个结点的阶乘,最后再求和即可。
不过在遍历单链表时要注意边界条件。
/**
* 求某个数的阶乘
* @param num 数
* @return num!
*/
int Factorial(int num) {
int res = 1.0;
// 0!=1
if (num == 0) {
return 1;
}
for (int i = 1; i <= num; ++i) {
res *= i;
}
return res;
}
/**
*
* @param
* @return
*/
int FactorialSum(List L) {
int sum = 0;
int value = 0; //存放结点的数据域Data
PtrToNode tmp = L;
//结点不为空
while (tmp != NULL) {
value = tmp->Data;
if (value == 0) {
//若为0,则直接加1,因为0!=1
sum += 1;
} else {
//求某个数的阶乘
int factorial = Factorial(value);
sum += factorial;
}
tmp = tmp->Next;
}
return sum;
}
7、统计某类完全平方数
本题要求实现一个函数,判断任一给定整数N
是否满足条件:它是完全平方数,又至少有两位数字相同,如144、676等。
函数接口定义:
int IsTheNumber ( const int N );
其中N
是用户传入的参数。如果N
满足条件,则该函数必须返回1,否则返回0。
裁判测试程序样例:
#include <stdio.h>
#include <math.h>
int IsTheNumber ( const int N );
int main()
{
int n1, n2, i, cnt;
scanf("%d %d", &n1, &n2);
cnt = 0;
for ( i=n1; i<=n2; i++ ) {
if ( IsTheNumber(i) )
cnt++;
}
printf("cnt = %d\n", cnt);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
105 500
输出样例:
cnt = 6
题解:
/**
* 暴力破解
* 此题可分为两步:
* 1、判断某个数是不是完全平方数
* 2、判断某数至少有两位数字相同
* @param N
* @return
*/
int IsTheNumber(const int N) {
int i = 0;
int num = 0;
while (1) {
//计算i的平方
num = i * i;
//如果num对于N,则表示该数不是完全平方数,return 0
if (num > N) {
return 0;
}
//该数是完全平方数
if (num == N) {
// 分别拿到该数的每个位的数,count数组索引存储对应的数
// 如count[1]存储数字1出现的次数
int count[10] = {0};
while (num != 0) {
/**
* num % 10 可以拿到最低位的数,如123 % 10 = 3
* num /10 可以抹去最低位的数,如123 /10 = 12
*/
int tmp = num % 10;
count[tmp]++;
//遍历count[],如果某个数的count[]存在两位数,则return 1
for (int j = 0; j < 10; ++j) {
if (count[j] >= 2) {
return 1;
}
}
num /= 10;
}
}
//i递增
i++;
}
}
8、简单阶乘计算
本题要求实现一个计算非负整数阶乘的简单函数。
函数接口定义:
int Factorial( const int N );
其中N
是用户传入的参数,其值不超过12。如果N
是非负整数,则该函数必须返回N
的阶乘,否则返回0。
裁判测试程序样例:
#include <stdio.h>
int Factorial( const int N );
int main()
{
int N, NF;
scanf("%d", &N);
NF = Factorial(N);
if (NF) printf("%d! = %d\n", N, NF);
else printf("Invalid input\n");
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
5
输出样例:
5! = 120
题解:
本题难度不大,但是要注意,int占4个字节,题目限制了N的取值为0~12,所以尽管是12!,int也是能存放的,假设N再大,就要考虑用long long类型或者用数组来存放了,刚好第10道题考的就是这个点!
本题提供两种解题方法:递归和非递归。
/**
* 递归实现
* @param N
* @return
*/
int Factorial(const int N) {
//N大于12或者N小于等于0,返回0
if (N < 0 || N > 12) {
return 0;
}
//递归出口:0! = 1
if (N == 0 ) {
return 1;
}
//递归调用
return N * Factorial(N - 1);
}
/**
* 非递归实现
* @param N
* @return
*/
int Factorial(const int N) {
int res = 1.0;
//N大于12或者N小于等于0,返回0
if (N < 0 || N > 12) {
return 0;
}
// 0! = 1
if (N == 0) {
return 1;
}
//累乘
for (int i = 1; i <= N; ++i) {
res *= i;
}
return res;
}
9、统计各位数字
本题要求实现一个函数,可统计任一整数中某个位数出现的次数。例如-21252中,2出现了3次,则该函数应该返回3。
函数接口定义:
int Count_Digit ( const int N, const int D );
其中N
和D
都是用户传入的参数。N
的值不超过int
的范围;D
是[0, 9]区间内的个位数。函数须返回N
中D
出现的次数。
裁判测试程序样例:
#include <stdio.h>
int Count_Digit ( const int N, const int D );
int main()
{
int N, D;
scanf("%d %d", &N, &D);
printf("%d\n", Count_Digit(N, D));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
-21252 2
输出样例:
3
题解:
/**
* 空间换时间,计算出各位数出现的次数
* @param N
* @param D
* @return
*/
int Count_Digit(const int N, const int D) {
int num;
//N取绝对值
if (N < 0) {
num = N * (-1);
} else {
num = N;
}
/*
* count[]数组存放各位数出现的次数
* 如,count[9]表示数字9出现的次数
*/
int count[10] = {0};
int tmp;
//特殊情况,如果N为0
if (num == 0) {
count[0]++;
}
while (num != 0) {
/**
* num % 10 可以拿到最低位的数,如123 % 10 = 3
* num /10 可以抹去最低位的数,如123 /10 = 12
*/
tmp = num % 10;
count[tmp]++;
num = num / 10;
}
//返回数字D出现的次数
return count[D];
}
10、阶乘计算升级版(▲)
本题要求实现一个打印非负整数阶乘的函数。
函数接口定义:
void Print_Factorial ( const int N );
其中N
是用户传入的参数,其值不超过1000。如果N
是非负整数,则该函数必须在一行中打印出N
!的值,否则打印“Invalid input”。
裁判测试程序样例:
#include <stdio.h>
void Print_Factorial ( const int N );
int main()
{
int N;
scanf("%d", &N);
Print_Factorial(N);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
15
输出样例:
1307674368000
题解:
这道题是唯一卡住的题,一开始没注意输入数值的范围是1~1000,直接用累乘去做,结果不能通过所有测试点,当N足够大时,输出结果是0,仔细一想是数值溢出问题。于是我换了long long类型存放计算结果,但还是不能通过测试点。
分析:
8字节 = 64bit,2^64 = 2^10 * 2^10 * 2^10 * 2^10 * 2^10 * 2^10 * 2^4
2^10 = 1024 近似看成1000(10^3),所以,2^64大概在 10^19 这个数量级上
但是1000! = 1000 * 999 *998 * ... * 3 * 2 * 1
因此,缩小看成1000个100相乘,即 100^1000,其结果大概是 10^2000 这个数量级。
显然,1000! 的结果,常规的数据类型是存放不下的。
所以,此题我们用数组来存放结果。
例如,123456789,我们逆序存放在数组中,即a[0]存放9……
以 279 x 69 为例子
假设279是前面某个阶乘的结果,已经逆序存放在num[]数组中,即:
num[0] = 9
num[1] = 7
num[2] = 2
/**
* 逆序打印数组
* @param num 数组
* @param length 数组长度
*/
void reversePrintArr(int num[], int length) {
for (int i = length - 1; i >= 0; i--) {
printf("%d", num[i]);
}
printf("\n");
}
void Print_Factorial(const int N) {
if (N < 0 || N > 1000) {
printf("Invalid input");
return;
}
//保存阶乘结果的num[]数组
int num[3000] = {0};
//0!=1
num[0] = 1;
//num[]数组的长度
int numLength = 1;
//阶乘,循环N次
for (int i = 1; i <= N; i++) {
//抹去最低位后余下的数,如num=552,则remainNum=55
int remainNum = 0;
for (int j = 0; j < numLength; j++) {
//数组的每个元素乘以i
int tmp = i * num[j] + remainNum;
num[j] = tmp % 10;
remainNum = tmp / 10;
}
// num[]数组遍历完成,将remainNum存放到num[]中
while (remainNum != 0) {
num[numLength] = remainNum % 10;
numLength++;
remainNum /= 10;
}
}
//输出结果
reversePrintArr(num, numLength);
}
11、求自定类型元素序列的中位数
本题要求实现一个函数,求N
个集合元素A[]
的中位数,即序列中第⌊(N+1)/2⌋大的元素。其中集合元素的类型为自定义的ElementType
。
函数接口定义:
ElementType Median( ElementType A[], int N );
其中给定集合元素存放在数组A[]
中,正整数N
是数组元素个数。该函数须返回N
个A[]
元素的中位数,其值也必须是ElementType
类型。
裁判测试程序样例:
#include <stdio.h>
#define MAXN 10
typedef float ElementType;
ElementType Median( ElementType A[], int N );
int main ()
{
ElementType A[MAXN];
int N, i;
scanf("%d", &N);
for ( i=0; i<N; i++ )
scanf("%f", &A[i]);
printf("%.2f\n", Median(A, N));
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
3
12.3 34 -5
输出样例:
12.30
题解:
最直观的解法就是,先将集合进行排序,之后返回符合题目的元素即可。
但是排序的算法有很多种,我们应该选择哪一种呢?此处我们就要考虑算法的时间的复杂度了。像冒泡排序、简单插入排序等算法会比较慢,当N比较大时可能会卡时,最后一个点会过不去。
此处,我使用的快速排序,原因是这个算法我比较熟悉,同时这个算法也比较快。一般都是默认以序列的第一个作为枢轴(基准)进行快速排序,但是,对于某些基本有序的序列,快速排序会退化成冒泡排序。
所以,此处要对快速排序进行简单的优化,其实很简单,只需要随机选择序列中的一个数作为枢轴即可,就可以起到优化的作用。
/**
* 交换数组两个索引下标的值
* @param a 数组
* @param i 索引1
* @param j 索引2
*/
void swap(ElementType a[], int i, int j) {
ElementType tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
/**
* 快速排序
* @param a 待排序序列
* @param low 左端点
* @param high 右端点
*/
void QuickSort(ElementType a[], int low, int high) {
if (low < high) {
int pivotIndex = Partition(a, low, high);
QuickSort(a, low, pivotIndex - 1);
QuickSort(a, pivotIndex + 1, high);
}
}
/**
* 枢轴的位置索引,需要优化快速排序(随机基准)
* @param a
* @param low
* @param high
* @return
*/
int Partition(ElementType a[], int low, int high) {
// int randIndex = rand() % (high - low) + low;
// swap(a, low, randIndex);
/**
* 快排优化,随机基准值,因为题目没有引入<cstdlib>
* 因此,取中间的数为枢轴即可完成优化
*/
swap(a, low, (low + high) / 2);
ElementType pivot = a[low];
while (low < high) {
while (low < high && a[high] > pivot) {
high--;
}
a[low] = a[high];
while (low < high && a[low] < pivot) {
low++;
}
a[high] = a[low];
}
a[low] = pivot;
return low;
}
/**
* 常规思路:排序(快排)+返回中位数
* @param A
* @param N
* @return
*/
ElementType Median(ElementType A[], int N) {
QuickSort(A, 0, N - 1);
//返回 (N+1)/2 的元素,其索引即为N/2
return A[N / 2];
}
12、判断奇偶性
本题要求实现判断给定整数奇偶性的函数。
函数接口定义:
int even( int n );
其中n
是用户传入的整型参数。当n
为偶数时,函数返回1;n
为奇数时返回0。注意:0是偶数。
裁判测试程序样例:
#include <stdio.h>
int even( int n );
int main()
{
int n;
scanf("%d", &n);
if (even(n))
printf("%d is even.\n", n);
else
printf("%d is odd.\n", n);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:
-6
输出样例1:
-6 is even.
输入样例2:
5
输出样例2:
5 is odd.
题解:
本题难度不大,提供两种解法。
/**
* 判断某个数n是否为奇数
* n % 2 = 0 --> n是偶数
* n % 2 = 1 --> n是奇数
* @param n
* @return
*/
int even(int n) {
//偶数
// if (0 == n % 2) {
// return 1;
// }
// //奇数
// return 0;
//等价的简易写法
return n % 2 == 0 ? 1 : 0;
}
/**
* 位运算
* n % 2 的本质,其实是保留二进制数n的最低位
* 如,9 % 2 = 1,9的二进制为1001,最低为1,所以9是奇数
* 如,10 % 2 = 0,8的二进制为1010,最低位为0,所以10是偶数
* 所以,我们将n为1进行与运算,即n & 1,即可保留最低位
* @param n
* @return
*/
int even(int n) {
return (n & 1) == 0 ? 1 : 0;
}
13、折半查找
给一个严格递增数列,函数int Search_Bin(SSTable T, KeyType k)用来二分地查找k在数列中的位置。
函数接口定义:
int Search_Bin(SSTable T, KeyType k)
其中T是有序表,k是查找的值。
裁判测试程序样例:
#include <iostream>
using namespace std;
#define MAXSIZE 50
typedef int KeyType;
typedef struct
{ KeyType key;
} ElemType;
typedef struct
{ ElemType *R;
int length;
} SSTable;
void Create(SSTable &T)
{ int i;
T.R=new ElemType[MAXSIZE+1];
cin>>T.length;
for(i=1;i<=T.length;i++)
cin>>T.R[i].key;
}
int Search_Bin(SSTable T, KeyType k);
int main ()
{ SSTable T; KeyType k;
Create(T);
cin>>k;
int pos=Search_Bin(T,k);
if(pos==0) cout<<"NOT FOUND"<<endl;
else cout<<pos<<endl;
return 0;
}
/* 请在这里填写答案 */
###输入格式:
第一行输入一个整数n,表示有序表的元素个数,接下来一行n个数字,依次为表内元素值。 然后输入一个要查找的值。
###输出格式:
输出这个值在表内的位置,如果没有找到,输出"NOT FOUND"。
输入样例:
5
1 3 5 7 9
7
输出样例:
4
输入样例:
5
1 3 5 7 9
10
输出样例:
NOT FOUND
题解:
折半查找,又称二分查找,是常用的查找算法之一。
/**
* 二分查找
* @param T
* @param k
* @return
*/
int Search_Bin(SSTable T, KeyType k) {
int low = 1;
int high = T.length;
int mid = 0;
while (low < high) {
mid = (high + low) >> 1;
if (k < T.R[mid].key) {
//k在mid左边
high = mid - 1;
} else if (k > T.R[mid].key) {
//k在mid右边
low = mid + 1;
} else if (k == T.R[mid].key) {
//返回位序,因为数组索引从1开始,所以索引等于位序
return mid;
}
}
return 0;
}
14、总结
题目都比较基础,基本不涉及数据结构和算法。尽管基本所有题目都能AC,但是并不代表就是最优解,因为本人水平有限,仅仅只是提供一个解题思路而已。
注:如有错误,敬请指正!