刷题平台:https://judge.u-aizu.ac.jp

Github项目:https://github.com/pengng/AIZU_ONLINE_JUDGE

4年前我还是用c语言刷题,现在已经开始用c++。原因是c++有STL,里面包含了一些常用的数据结构的实现,包括栈、队列、链表等。这样方便解一些复杂的题目时,不用再去自己实现基础的数据结构。

另外,开始使用Visual Studio开发工具代替以前的Sublime Text,创建项目、编译和断点调试会方便很多。

这个刷题平台不同于的LeetCode,它解题时需要自己处理标准输入/输出,而LeetCode只需要实现算法核心,输入则通过函数参数传入。

c的标准库到了c++下面的命名有了些变化,头文件名开头带了”c”,并且不需要结尾的”.h” 。例如:在c语言中<math.h>头文件在c++下变成<cmath>;<ctype.h>则变成<cctype>。

1.排序3个数字

输入3个整数,输出它们的升序排列,数字间用1个空格分隔,用换行符结尾。如下图所示:

排序3个数字

#include <stdio.h>
void
priArr(int [], int);
void
sort(int [], int);
int
main(void)
{
    int arr[3];
    scanf("%d %d %d", arr, arr + 1, arr + 2);
    sort(arr, 3);
    priArr(arr, 3);
    return 0;
}
void
priArr(int arr[], int len)
{
    int i = 0;
    printf("%d", arr[i++]);
    for ( ; i < len; i++)
        printf(" %d", arr[i]);
    putchar('n');
}
void
sort(int arr[], int len)
{
    int i, j, tmp;
    for (i = 1; i < len; i++) {
        tmp = arr[i];
        for (j = i - 1; j >= 0 && arr[j] > tmp; j--) {
            arr[j + 1] = arr[j];
        }
        arr[j + 1] = tmp;
    }
}

后来觉得3个数字排序这种特例可以不用特地写一个排序函数,并且用数组来存储它们,所以用c++重新写。如下所示:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
	int a, b, c;
	cin >> a >> b >> c;
	if (a > b)
	{
		swap(a, b);
	}
	if (a > c)
	{
		swap(a, c);
	}
	if (b > c)
	{
		swap(b, c);
	}
	cout << a << " " << b << " " << c << endl;
}

程序结尾输出了\(a,b,c \)三个数字,并且满足\(a \leq b \leq c \)。程序包含3个if结构:

  1. 第1个 if 执行之后,如果 \(a > b \) ,则交换 a 和 b 的值,此时满足 \(a \leq b \) ;
  2. 第2个 if 执行之后,如果 \(a > c \) ,则交换 a 和 c 的值,此时满足 \(a \leq b \) 且 \(a \leq c \) ;
  3. 第3个 if 执行之后,如果 \(b > c \) ,则交换 b 和 c 的值,此时满足 \(a \leq b \) 且 \(a \leq c \) 且 \(b \leq c \),即 \(a \leq b \leq c \)。

对于”交换两个值“这样的常规操作,c++的标准库就包含了swap函数,这挺好的。

2.最小值,最大值和求和

输入n个整数,输出其中的最小值,最大值和这些值的总和。
最大值,最小值和求和

最小值和最大值需要一个初始值,所以按照题目用#define宏定义了MIN和MAX。在c++版本的程序中,不再使用宏来定义,而是用<climits>中定义了的INT_MAX和INT_MIN。

#include <stdio.h>
#define MIN -1000000
#define MAX 1000000
int
main(void)
{
    int min = MAX;
    int max = MIN;
    int num, c;
    long long sum = 0;
    scanf("%d", &c);
    while (c--) {
        scanf("%d", &num);
        sum += num;
        min = num < min ? num : min;
        max = num > max ? num : max;
    }
    printf("%d %d %lldn", min, max, sum);
    return 0;
}
#include<iostream>
#include<climits>
using namespace std;
int main() {
	int minimum = INT_MAX;
	int maximum = INT_MIN;
	long long sum = 0LL;
	int x, n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> x;
		sum += x;
		if (x < minimum) minimum = x;
		if (x > maximum) maximum = x;
	}
	cout << minimum << " " << maximum << " " << sum << endl;
}

3.倒序数字

将输入的n个整数倒序后输出。

倒序数字序列

原来c语言版本用的是动态数组,使用<stdlib.h>中的malloc函数来申请内存空间。后来觉得题目的n上限值较小(\(n \leq 100 \)),直接用这个上限当常数,做数组的固定大小即可。

用malloc并不能节约多少内存空间。同时数组中的各个数字范围较小,也可以用short int类型存储,但也因为n较小,而同样节约不了多少空间。

#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
    int n, num;
    int i = 0;
    int * arr;
    scanf("%d", &n);
    arr = (int *) malloc(n * sizeof(int));
    while (i < n)
        scanf("%d", arr + i++);
    printf("%d", arr[--n]);
    while (n--)
        printf(" %d", arr[n]);
    putchar('n');
    free(arr);
    return 0;
}

c++版本则是利用递归的性质,将数字序列倒序输出。

#include<iostream>
using namespace std;
void fn(int n) {
	int x;
	cin >> x;
	if (--n > 0) fn(n);
	if (n > 0) cout << " ";
	cout << x;
}
int main() {
	int n;
	cin >> n;
	fn(n);
	cout << endl;
}

4.矩阵乘法

输入\(n, m, l \)和矩阵\(A_{nm} \),以及矩阵\(B_{ml} \)。输出两个矩阵的乘积\(A_{nm}B_{ml} \)。

矩阵乘法

c语言用动态数组,而c++版本则用静态数组。因为题目中\(1 \leq n,m,l \leq 100 \),也就是总的空间需要\(100 \times 100 \times 2 = 20,000 \)。

原来c版本用的是long long int类型,后来发现只需要单个数值是long long int即可,而数组项的类型可以用short int来节约空间。

#include <stdio.h>
#include <stdlib.h>

void
pri(long long **, long long **, int, int, int);

long long **
Malloc(int, int);

void
Scanf(long long * [], int, int);

int
main(void)
{
    int n, m, l;
    long long **matrixA, **matrixB;

    scanf("%d %d %d", &n, &m, &l);
    matrixA = Malloc(n, m);
    matrixB = Malloc(m, l);
    
    Scanf(matrixA, n, m);
    Scanf(matrixB, m, l);

    pri((long long **) matrixA, (long long **) matrixB, n, m, l);
    return 0;
}

void
pri(long long **a, long long **b, int n, int m, int l)
{
    int i, j, k;
    long long sum;
    for (i = 0; i < n; i++)
        for (j = 0; j < l; j++) {
            sum = 0;
            for (k = 0; k < m; k++)
                sum += a[i][k] * b[k][j];
            printf("%lld", sum);
            if (j == l - 1)
                putchar('\n');
            else
                putchar(' ');
        }
}

long long **
Malloc(int n, int m)
{
    int i;
    long long **arr = (long long **) malloc(sizeof(long long *) * n);
    for (i = 0; i < n; i++)
        arr[i] = (long long *) malloc(sizeof(long long) * m);

    return arr;
}

void
Scanf(long long *arr[], int n, int m)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < m; j++)
            scanf("%lld", *(arr + i) + j);
}

注意:计算矩阵的每一项时,需要用long long int类型。因为\(1 \leq a_{ij}, b_{ij} \leq 10,000 \),所以\(1 \leq c_{ij} \leq 10,000,000,000 \)已经超过int类型的表示范围。

#include<iostream>
using namespace std;

int main() {
    int n, m, l;
    short A[100][100], B[100][100];

    cin >> n >> m >> l;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> A[i][j];
        }
    }

    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < l; j++)
        {
            cin >> B[i][j];
        }
    }

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < l; j++)
        {
            long long sum = 0LL;
            for (int k = 0; k < m; k++)
            {
                sum += A[i][k] * B[k][j];
            }
            if (j > 0) cout << " ";
            cout << sum;
        }
        cout << endl;
    }
}

5.切换大小写

输入一个字符串,输出一个字符串,其中大写字母转成小写字母,小写字母转成大写字母。

切换大小写

#include <stdio.h>

int
main(void)
{
    char ch;
    while ((ch = getchar()) != EOF)
        if (ch >= 'A' && ch <= 'Z')
            putchar(ch - 'A' + 'a');
        else if (ch >= 'a' && ch <= 'z')
            putchar(ch - 'a' + 'A');
        else
            putchar(ch);
    return 0;
}

c语言是通过自己计算的,c++版本则使用标准库<cctype>中的islower、isupper、tolower、toupper函数。

#include<iostream>
#include<cctype>
using namespace std;

int main() {
    char c;
    
    while (cin.get(c))
    {
        if (isupper(c)) cout << (char)tolower(c);
        else if (islower(c)) cout << (char)toupper(c);
        else cout << c;
    }
}