编程学习
博客里已经有Rust学习了,但那个准备更一些从零开始学习的东西
这篇博客就记录一下我在刷牛客和leetcode时,发现的一些小知识吧,因为不限语言,所以叫做编程学习
1.牛客 CPP11判断季节
题目:CPP11判断季节
这里我首先想到的解法是使用 if - else 判断结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>
using namespace std;
int main() {
int month;
cin >> month;
if (month == 3 || month == 4 || month == 5) {
cout << "春季";
} else if (month == 6 || month == 7 || month == 8) {
cout << "夏季";
} else if (month == 9 || month == 10 || month == 11) {
cout << "秋季";
} else if (month == 1 || month == 2 || month == 12) {
cout << "冬季";
} else {
cout << "不合法";
}
return 0;
}
|
但总感觉这样实现不太优雅,看题解发现有人使用switch 判断结构:
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
|
#include <iostream>
#include <ostream>
using namespace std;
int main() {
int month;
cin >> month;
switch (month) {
case 1:
case 2:
case 12:
cout << "冬季" << endl;
break;
case 3:
case 4:
case 5:
cout << "春季" << endl;
break;
case 6:
case 7:
case 8:
cout << "夏季" << endl;
break;
case 9:
case 10:
case 11:
cout << "秋季" << endl;
break;
default:
cout << "不合法" << endl;
}
return 0;
}
|
但是这样写得还是有点不太优雅
最后看最高赞题解是这样,同样是switch 判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <iostream>
using namespace std;
int main() {
int month;
cin >> month;
if(month < 1 || month > 12) //优先判断是否合法月份
cout << "不合法" << endl;
else{
switch(month){ //根据月份判断
case 3 ... 5: //连续的值
cout << "春季" << endl; break;
case 6 ... 8:
cout << "夏季" << endl; break;
case 9 ... 11:
cout << "秋季" << endl; break;
default:
cout << "冬季" << endl;
}
}
return 0;
}
|
这样写的原因是,首先为了避免使用麻烦的 if - else ,选择使用switch , 而且因为是判断季节,月份的值大多是连续的,所以可以使用case的连续写法:在case中,可以用x…y表示范围在 [x,y] 的值,两边都是闭区间。
所以在代码中 case3: case4: case5: 就变成了 case 3...5: 最后冬季不连续,就使用 default 代替,由于已经使用 if 将月份值限制在 1 - 12范围内,除去以上三种情况就剩冬季了
2.牛客 CPP12 求 1~n之间偶数的和
题目: CPP12 求 1~n之间偶数的和
好久没写了连while的用法都忘了,按理说以前这个同样在牛客上用rust写过,应该是不能忘的QAQ
while 循环和 for 循环本质是同一种循环的两种不同形式
while 循环事先只设定好了循环的终点,在此范围内不断执行语句,具体其他的限制条件在循环内部定义
for 循环则事先设定好了循环的终点,以及循环的规则(如 i++ 设定在循环外)
因此while循环要比 for 循环稍微灵活一些
在Rust 中,在程序编译时,编译器会把 while 去糖化变成 “一个无限循环 + 一个条件判断和 break” ,类似于这样:
1
2
3
4
5
|
let mut i = 0;
while i < 10 {
println!("{}", i);
i += 1;
}
|
在 MIR 层面,它会被转换成类似下面这样的逻辑:
1
2
3
4
5
6
7
8
9
10
|
let mut i = 0;
loop {
if i < 10 {
// 循环体
println!("{}", i);
i += 1;
} else {
break; // 条件不满足,退出循环
}
}
|
同样的,编译器也会对 for 循环做相似的去糖化处理:
去糖化过程:for -> while let -> loop
Rust 中的 for 循环之所以强大和灵活,是因为它本质上是在遍历一个迭代器(Iterator),因此,任何一个 for 循环都会被编译器转换成一个使用 while let 和迭代器的等价结构
- 牛客 CPP13 计算一个数的阶乘
CPP13 计算一个数的阶乘
最适合区分递归和迭代的题目,但我只想到了迭代的实现,忘记递归是怎么实现的了
迭代:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
long long factorial = 1;
for (int i = 2; i <= n; i++) {
factorial *= i;
}
cout << factorial << endl;
return 0;
}
|
递归:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream>
using namespace std;
long long fac(int n) {
if (n == 1) {
return 1;
}
return fac(n-1) * n;
}
int main() {
int n;
cin >> n;
long long factorial = fac(n);
cout << factorial << endl;
return 0;
}
|
这里遇见了一个小小的问题,C++中函数声明必须在调用前,但Rust就不需要
这里写一下相同的问题使用Rust是如何解决的:
迭代:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
use std::io;
fn main() {
let mut stdin = String::new();
io::stdin().read_line(&mut stdin).expect("");
let n = stdin
.trim()
.parse()
.expect("");
let mut x = 1;
for i in 2..=n {
x *= i;
}
println!("{}", x);
}
|
递归:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
use std::io;
fn main() {
let mut stdin = String::new();
io::stdin().read_line(&mut stdin).expect("");
let n = stdin
.trim()
.parse()
.expect("");
let x = factorial(n);
println!("{}", x);
}
fn factorial(n: i64) -> i64 {
if n == 1 {
return 1;
}
return n * factorial(n - 1);
}
|