拜读了迟来的grown大佬的刷题笔记,也想自己写一写,故有此篇。
题目描述
给定一个范围 [L,R],求出数字2在该区间内出现的次数。(其中1≤L≤R≤10000)
显然数字2在2中出现1次,在12中出现1次,在20中出现1次,在22中算出现2次。
要求输入共1行,为两个正整数L和R,中间用一个空格隔开。
输出共1行,表示数字2出现的次数。
示例1 | 示例2 |
---|---|
输入:2 22 | 输入:2 100 |
输出:6 | 输出:20 |
思路
逐位拆分。
我的解答
#include <stdio.h>
int count(int left,int right); //声明count函数
int main(){
int Left,Right; //存放边界
int num; //存放次数
scanf("%d%d",&Left,&Right); //通过键盘获取边界值
num = count(Left,Right); //调用count()函数统计次数,num接收返回值
printf("%d",num); //输出次数值到屏幕
return 0;
}
//count()函数的实现
int count(int left,int right){
int account = 0;
for(int i = left; i <= right; i++){
int num = i;
//变0相当于每一位都被判断过了。
while(num > 0){
if(num % 10 == 2) account++;
num /= 10; //除法减少1位,开始准备判断倒数第二位
}
}
return account;
}
感想记录
没看大佬思路的时候完全没想到可以通过和10的取余运算判断个位是不是2,以及可以通过除10的整数除法来去掉个位,把原本的十位变成个位继续判断。
想记录一下scanf("%d%d",&Left,&Right);
这个语句,只要我输入第一个数后,输空格,接下来输的数字计算机就知道是给第二个 %d
的,而输入回车后它知道输入结束了,开始读取,好神奇。
这么说可以用scanf()从键盘一次性读入多个需要的int
信息,输入时只要用空格隔开。
📌 拓展:%s
的详细规则
- 读取字符串前,自动忽略所有的空白字符(包括空格、制表符
\t
、换行符\n
和回车符\r
等等)。准确地说,是忽略已经呈现为了空白状态的它们,比如按下空格键、tab键、回车键这些操作。 - 遇到任意空白字符时,%s停止读取,剩余内容留在输入缓冲区等待后续处理。
- 因此,scanf不能读取含空格的字符串。
- 在C语言中,字符串中的转义字符(如\t、\n)只有在源代码中出现时才会被编译器处理为控制字符。而在运行时,从标准输入读取的字符并不会被自动转换。也就是说,用户在键盘上输入反斜杠和t,会被视为两个独立的字符,而不是一个制表符。
- 如何正确输入控制字符? 在终端中,按Tab键会生成制表符(ASCII 0x09),而按Enter生成换行符(0x0A)。
为什么int num = i;要定义在循环内部,而不是在循环外定义,然后每次循环只赋值
1、变量定义的位置对性能没有太大影响
循环内定义意味着每次循环都会为 num 分配内存并初始化。但现代编译器(如 GCC、Clang)会自动进行优化:
- 寄存器分配:对于简单的 int 类型变量,尤其还要频繁访问,编译器可能直接将 num 存储在寄存器中,而非内存。
- 复用空间:即使分配在栈上,同一变量在循环中的内存地址通常是固定的,不会频繁申请/释放。
分别在循环外和循环内定义num,测试 1 亿次循环,两种方式的运行时间几乎完全相同。
循环内的主要性能消耗是 num % 10 和 num /= 10 的除法和取模运算,而非变量定义。真正的性能优化应集中在 算法复杂度(如减少循环次数)和减少高开销操作(如除法) 上。
2、循环内定义变量的好处
- 可以把它的作用域限制在循环内部
- 避免循环外的变量污染
- 避免变量在循环外被误修改
- 有助于增强代码的可读性和安全性
- 有利于代码的长期维护