0%

oj题目记录

判断闰年:

判断某个年份是不是闰年,如果是闰年,请输出yes,否则请输出no

输入: 一行,只有一个整数x (0<=x <=10000)

输出: 只有一行字符

闰年:
1.年份能被4整除并且不能被100整除
2.年份能被400整除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {

int year = 0;
scanf("%d", &year);
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
printf("yes");
}
else {
printf("no");
}
return 0;
}

判断回文数

输入一个整型数,判断是否是对称数,如果是,输出yes,否则输出no,不用考虑这个整型数过大,int类型存不下,不用考虑负值;

例如 12321是对称数,输出yes,124421是对称数,输出yes,1231不是对称数,输出no

原数 == 反转后的数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {

int i = 0;
int i2 = 0;
int tmp = 0;
scanf("%d", &i);
i2 = i;
while (i) {
tmp = tmp * 10 + i % 10;
i = i / 10;
}
if (tmp == i2) {
printf("yes");
}
else {
printf("no");
}

return 0;
}

逆转字符串

读取一个字符串,字符串可能含有空格,将字符串逆转,原来的字符串与逆转后字符串相同,输出0,原字符串小于逆转后字符串输出-1,大于逆转后字符串输出1。例如输入 hello,逆转后的字符串为 olleh,因为hello 小于 olleh,所以输出-1

输入一个字符串,例如 hello,当然输入的字符串也可能是 how are you,含有空格的字符串

输出是一个整型数,如果输入的字符串是hello,那么输出的整型数为-1

键盘输入的字符串,系统会自动加上 ‘\0’

自定义的字符串需要手动加上 ‘\0’ 表示字符串结尾

strcspn(char *str1,char *str2)

str c spn [c -> complement(补集,不包含),spn ->span(连续长度)]

函数返回str1 开头连续n个字符都不含字符串str2内字符的字符数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main() {

char input[100];
fgets(input, 100, stdin);
input[strcspn(input, "\n")] = '\0'; // 去掉换行
char output[100];
for (int i = 0; i < strlen(input); i++) {
output[i] = input[strlen(input) -1-i];
}
output[strlen(input)] = '\0';

/*fputs(output, stdout);
printf("\n");*/
int result = strcmp(input, output);

if (result < 0)
{
printf("%d\n", -1);
}
else if (result > 0)
{
printf("%d\n", 1);
}

else {
printf("%d\n", 0);
}

return 0;
}

如果不去掉 input的’\n’,那么’\n’也会跟着被反转

换钞票

某人想将手中的一张面值100元的人民币换成10元、5元、2元和1元面值的票子。要求换正好40张,且每种票子至少一张。问:有几种换法?

循环结构的嵌套

注: “= ”是赋值,“== ”是关系运算符

题目有两个限制:

  1. 钱的总张数 = 40

  2. 每张票子都得有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

//换货币

int main() {

int result = 0;
int count = 0;
// 要求换正好40张
// 100 换成 10,5,2,1
int k = 0;
int m = 0;
int j = 0;
int s = 0;
for (k = 1; k < 11; k = k + 1) {
/*result = k * 10 + m * 5 + j * 2 + s * 1;*/
for ( m = 1; m < 21; m = m + 1) {
//result = k * 10 + m * 5 + j * 2 + s * 1;
for ( j = 1; j < 51; j = j + 1) {
//result = k * 10 + m * 5 + j * 2 + s * 1;
for ( s = 1; s < 101; s = s + 1) {
result = k * 10 + m * 5 + j * 2 + s * 1;
// 赋值运算符
if (result == 100 && (k+m+j+s == 40)) {
count ++;
}


}

}
}

}
printf("%d", count);
return 0;
}

枚举思想(暴力法)

面对一个问题时,直接将问题的所有可能性全部列出,一个一个的去检查是否符合题目的要求

故 枚举思想的核心便是用 循环结构 (for,while)去解决问题

找完数

完数是指除本身以外的因子之和等于其本身的数。

任给一个自然数n,求n以内的所有完数。如果找不到,则输出”No”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main() {
// 找完数
int n = 0;

scanf("%d", &n);
if (0 < n < 10000) {
// 逐个循环
for (int k = 1; k < n + 1; k++) {
//找单个的因子
int sum = 0;
for (int i = k - 1; i > 0; i--) {
if (k % i == 0) {
sum += i;
}
}
if (sum == k) {
printf("%d\n", k);
}
}

}
else {
printf("输入值有误,请输入 0-10000 之间的值");
}


return 0;
}

水仙花数

“水仙花数”是指一个三位数,其各位数字的立方和等于该数本身。例如,153是一个水仙花数,因为 1³ + 5³ + 3³ = 153。

请编写程序,找出所有的三位水仙花数。

注意: pow(i,3) 函数的返回值是 double 数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {

int m = 0;
for (int i = 1; i < 10; i++) {
for (int k = 0; k < 10; k++) {
for (int j = 0; j < 10; j++) {
m = i * 100 + k * 10 + j;
if (i*i*i + j * j * j + k * k * k == m) {
printf("%d\n", m);
}
}
}
}
return 0;
}

分治思想

无法从全局解决问题,那就从局部解决问题,这便是分治法(分而治之)

大问题转移到小问题,小问题有解决方法

爬楼梯

假设你正在爬一个楼梯。它总共有n 阶台阶,每次你只能爬 1 阶,或者爬 2 阶

问:你有多少种不同的方法可以爬到楼顶

num为 n 的数量 = num 为 n-1 的数量 + num 为 n-2 的数量

当n >2 时,最后一步要么跨1个台阶,要么跨2个台阶,两者互斥

逐级往下分

假设n = 5,f(5) = f(3) 【最后一步跨两个台阶】+ f(4)【最后一步跨一个台阶】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int f(int n) {
if (n > 2) {
int result = f(n - 1) + f(n - 2);
return result;
}
else if(n == 2){
return 2;

}
else if (n == 1) {
return 1;
}
}

int main() {
int n = 4;
printf("%d", f(n));
return 0;
}

汉诺塔问题

有 n 个从小到大排列的圆盘,需要将圆盘全部就移动到另一个柱子上,并遵守:

  1. 每次只能移动一个圆盘

  2. 移动过程中,大盘不能放在小盘上面

  3. 只能移动最顶端的圆盘

大问题:

将上面的 前 n-1 个盘子 从 A移动到B

将下面的 n 个盘子从 A移到 C

将 n-1 个盘子从 B移到 C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void hanoi(int n, char from, char buffer, char to) {
if (n > 1) {
//前 n - 1个圆盘 从 from 到 buffer
hanoi(n - 1, from, to, buffer);
// 第n 个盘子从 form 到 to
hanoi(1, from, buffer, to);
// 前 n - 1个圆盘 从 buffer 到 to
hanoi(n - 1, buffer, from, to);
}
else if (n == 1) {
printf("move %c to %c\n", from, to);
}
}

int main() {
int n = 4;
hanoi(n, 'A', 'B', 'C');
return 0;
}

归并排序

对一个无序数组,进行排序

大问题转移成小问题;

左侧和右侧分别是有序的数组后进行合并

小问题:

当数组只有 1 个元素的时候(left == right)数组字然有序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 归并排序
void merge(int* arr, int* temp, int left, int right, int mid) {
// 将 arr 的内容备份到 tmp中
for (int i = left; i <= right; ++i) {
temp[i] = arr[i];
}

// i访问左半边,j访问右半边,k存放结果
int i, j, k;
for (i = left, j = mid + 1, k = left; i <= mid && j <= right; ++k) {
if (temp[i] < temp[j]) {
arr[k] = temp[i];
++i;
}
else {
arr[k] = temp[j];
++j;
}

}
while (i <= mid) {
arr[k] = temp[i];
++i;
++k;
}
while (j <= right) {
arr[k] = temp[j];
++j;
++k;
}
}

void mergeSort(int* arr, int* temp, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, temp, left, mid);
mergeSort(arr, temp, mid + 1, right);
merge(arr, temp, left, right, mid);

}
}

int main() {
int arr[] = { 6,5,9,8,2,3,4,7,10,1 };
int temp[10];
mergeSort(arr, temp, 0, 9);
return 0;
}

C++引用

c++ 的引用本质是为变量起了一个外号,在子函数中可以直接操作主函数变量

编译器需要改成 c++ 环境下

注: & 在不同的位置,不同的语境下,功能完全不同

在类型后面是外号(引用)char* &p_ref;

在变量前面是地址(取地址)&a,c++的引用;

在两数中间是计算(位运算)a & b

使用C++的引用,注意提交时把代码选为C++;在主函数定义字符指针 char *p,然后在子函数内malloc申请空间(大小为100个字节),通过fgets读取字符串,然后在主函数中进行输出;要求子函数使用C++的引用,注意在C++中从标准输入读取字符串,需要使用fgets(p,100,stdin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// char* &p 代表 p 是 main 函数里指针变量的别名
void func(char*& p) {
p = (char*)malloc(100);
fgets(p, 100, stdin);
}

int main() {
char* p = NULL;
func(p);

if (p != NULL) {
printf("%s", p);
free(p);
}
return 0;
}

scanf() 输出格式:

scanf() 中的 %c 不会忽略空白字符,故%c 会将空格符认为是输入

解决方法是:在“ %c” 前面加上空格,让其忽略空白字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct student_s {
int id;
char name[20];
char gender;
}student_t;



int main() {
student_t student;
scanf("%d %s %c",&student.id,student.name,&student.gender);

printf("%d %s %c", student.id, student.name, student.gender);
return 0;
}