一、OJ题目输入情况汇总
OJ(online judge)
接下来会有例题 , 根据一下题目 , 对这些情况进行分析
1.1 单组测试用例
单在 --> 程序运行一次 , 就处理一组
练习一:计算 (a+b)/c 的值
B2009 计算 (a+b)/c 的值 - 洛谷
#include <iostream> #include <cstdio> using namespace std; int main() { int a,b,c; cin >> a >> b >> c; cout << (a+b)/c << endl; return 0; }
复制
练习二:与 7 无关的数
B2081 与 7 无关的数 - 洛谷
这题也是多个测试点 , 但是运行一次 , 仅仅处理一组数据!
#include <iostream> #include <cstdio> using namespace std; int main() { int n; cin >> n; int i = 1 ; int sum = 0; while(i <= n) { if(i % 7 != 0 && i % 10 != 7 && i / 10 % 10 != 7) sum += (i*i); i++; } cout << sum << endl; return 0; }
复制
1.2 多组测试用例
多组 : 程序运行一次 , 处理多组 。就像我们前面做的题目 , n次访问。
测试数据组数已知:
练习一:多组输入 a+b||
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> using namespace std; int main() { int n; cin >> n; int a,b; while(n--) { cin >> a >> b; cout << a + b << endl; } return 0; }
复制
练习二:斐波那契数列
B2064 斐波那契数列 - 洛谷
#include <iostream> #include <cstdio> using namespace std; int main() { int n; cin >> n; int a = 0; int ret[40] = {0,1,1}; for(int i = 3; i<30; i++) { ret[i] = ret[i-1] + ret[i-2]; } while(n--) { cin >> a; cout<< ret[a] << endl; } return 0; }
复制
练习三:制糊串
B3769 [语言月赛202305] 制糊串 - 洛谷
#include <iostream> #include <cstdio> #include <string> using namespace std; int main() { string s,t; cin >> s >> t; int q = 0; cin >> q; int l1,r1,l2,r2; while(q--) { cin >> l1 >> r1 >> l2 >> r2; string s1 = s.substr(l1 -1 , r1 - l1 + 1); string s2 = t.substr(l2 -1 , r2 - l2 + 1); //比较 if(s1 > s2) cout << "erfusuer" <<endl; else if(s1 < s2) cout << "yifusuyi" << endl; else cout << "ovo" << endl; } return 0; }
复制
题目中说“有q次询问” , 意思是程序要处理q组数据 , (也就是对应q次循环) , 需要针对每一次的访问 , 给出一个结果。
就是之前的单组测试 变成了 q 组测试 , 在之前代码加上while 循环即可 。当进行q次访问的时候 , 使用while(q--) , 是非常方便的 !!!
测试数据组数未知:
练习一:多组输入a+b
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> #include <string> using namespace std; int main() { int a , b; while(cin >> a >> b) { cout << a + b << endl; } return 0; }
复制
这道题的难点就是 , 怎么去判断读取结束呢?
1 . cin >> a ; 会返回一个流对象的引用 , 即cin本身 在C++中 , 流对象可以被用作布尔值来检查流的状态。流的状态良好 --> true ; 发生错误(如遇到输入结束符或类型不匹配) -->false
2. 所以在while(cin >> a >> b) 语句中 , 流成功读取两个值 , 返回流对象cin 被转化为 true,循环继续 。如果读取失败 , 返回false , 循环停止 。
练习二:数字三角形
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> #include <string> using namespace std; int main() { int n; while(cin >> n) { for(int i = 1;i <= n;i++) { for(int j = 1;j <=i ; j++) { cout << j << " "; } cout << endl; } } return 0; }
复制
练习三:定位查找
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> #include <string> using namespace std; const int N = 25; int arr[N]; int main() { int n = 0; int m = 0; int i = 0; while(cin >> n) { //输入n组数据,存储在数组arr for( i = 0;i < n;i++) { cin >> arr[i]; } //处理数据 cin >> m; for( i = 0;i < n;i++) { if(arr[i] == m) { cout << i << endl; break;//找到第一个,直接结束这组数据查找 } } //走到这里,没有找到m //如果不加i==n,那么无论什么情况都会打印No if(i == n) cout << "No" << endl; } return 0; }
复制
注意 , 打印No的时候 , 需要条件 , 否则无论是否找到 , 都会打印No;
方法二 : 用一个flag ,记录是否找到
#include <iostream> #include <cstdio> #include <string> using namespace std; const int N = 25; int arr[N]; int main() { int n = 0; int m = 0; while(cin >> n) { int flag = 0; //输入n组数据,存储在数组arr for(int i = 0;i < n;i++) { cin >> arr[i]; } //处理数据 cin >> m; for(int i = 0;i < n;i++) { if(arr[i] == m) { cout << i << endl; flag = 1; break;//找到第一个,直接结束这组数据查找 } } //走到这里,没有找到m if(flag == 0) cout << "No" << endl; } return 0; }
复制
注意 : 这里的flag 需要放在while 循环体内 否则 , 一次循环结束 , flag 将不会被重置为0
特殊值结束测试数据:
练习一:字符统计
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> #include <string> using namespace std; //方法一 int main() { int ch; int Letters = 0; int Digits = 0; int Others = 0; while((ch = getchar()) != '?') { if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) Letters++; else if(ch >= '0' && ch <= '9') Digits++; else Others++; } cout << "Letters=" << Letters << endl; cout << "Digits=" << Digits << endl; cout << "Others=" << Others << endl; return 0; }
复制
灵活运用库函数 ---> isalpha 、 isdigit
记得加上头文件 <cctype>
#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; //方法二 -- 借助库函数isalpha、isdigit int main() { int ch; int Letters = 0; int Digits = 0; int Others = 0; while((ch = getchar()) != '?') { if(isalpha(ch)) Letters++; else if(isdigit(ch)) Digits++; else Others++; } cout << "Letters=" << Letters << endl; cout << "Digits=" << Digits << endl; cout << "Others=" << Others << endl; return 0; }
复制
方法三:直接输入整个字符 , 但问号不需要统计 , 那么可以借助 pop_back() , 来删掉问好
#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; //方法三 int main() { string s; int Letters = 0; int Digits = 0; int Others = 0; getline(cin,s); //此字符串是以?结束的,不想统计? s.pop_back() ; for(auto e:s) { if(isalpha(e)) Letters++; else if(isdigit(e)) Digits++; else Others++; } cout << "Letters=" << Letters << endl; cout << "Digits=" << Digits << endl; cout << "Others=" << Others << endl; return 0; }
复制
练习二:多组数据a+b III
登录—专业IT笔试面试备考平台_牛客网
#include <iostream> #include <cstdio> #include <string> using namespace std; int main() { int a,b; while(cin >> a >> b) { if(a==0 && b==0) break; cout << a+b << endl; } return 0; }
复制
方法二:借助逗号表达式
1) 从左到右依次计计算
2)整个表达式的结果是 最后一个表达式的结果
#include <iostream> #include <cstdio> #include <string> using namespace std; int main() { int a,b; while(cin >> a >> b,a&&b) { cout << a+b << endl; } return 0; }
复制
以下是逗号表达式的举例讲解 :
二、输入中的特殊技巧
2.1 技巧1:含空格字符串的特殊处理方式
根据我们已经所学的知识 , 处理含有空格的字符串 可以使用 : fgets , scanf , getchar , getline 。具体使用需要据题目分析 ,有时候只是为了读取单词 , 忽略空格 。
练习:统计数字字符个数
B2109 统计数字字符个数 - 洛谷
方法一:一次性处理整个字符串 ;然后再遍历字符串 , 如果是数字 , 就用计数器统计出来。
#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; //方法一:一次性处理整个字符串 int main() { string s; int c = 0; getline(cin,s); for(auto e:s) { if(isdigit(e)) c++; } cout << c << endl; return 0; }
复制
方法二 : 逐个字母处理
1 . cin 读取字符串的时候 , 遇到空格就会停止 ;借助这一个特点 , 在while (cin >> s ) 中 , 整个字符串如果遇到空格就会跳过 , 继续处理下一个单词 。
2 . 当cin 读取失败后 , 返回false , while 循环结束
#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; //方法二:逐个单词处理 int main() { int c = 0; string s; //cin 读取字符串的时候,不会读取空格 //遇到空格就停止 //运用cin的特性,while这里遇到空格就会跳过 while(cin >> s) { for(auto e:s) { if(isdigit(e)) c++; } } cout << c << endl; return 0; }
复制
2.2 技巧2:数字的特殊处理方式
当我们程序运行的时候 , 在控制台输入 123 的时候 , 这时候的 123 是3个字符,123是一个字符序列 , 程序会根据代码中的数据类型 , 可能将123解析成整型 , 也可能将123 解析成字符串 。
练习:小乐乐改数字
小乐乐改数字_牛客题霸_牛客网
#include <iostream> #include <cstdio> #include <string> #include <cmath> using namespace std; int main() { int n = 0; cin >> n; int ret = 0; int i = 0;//记录处理到多少位 while(n) { if(n % 10 % 2 != 0) ret += pow(10,i); n /= 10; i++; } cout << ret << endl; }
复制
#include <iostream> #include <cstdio> #include <string> #include <cmath> using namespace std; int main() { string s; cin >> s; for(int i = 0; i < s.size() ;i++) { if(s[i] % 2 == 0) { s[i] = '0'; } else s[i] = '1'; } cout << stoi(s) << endl; return 0; }
复制
三、scanf/printf 和 cin/cout 的区别
scanf 和 printf 是C语言中标准输入输出函数 , 而 cin 和 cout 是 C++语言中的标准输入输出流对象 。各自有优缺点 , 整体上来说 , cin 和 cout 会更加方便 ; 但是有时候不得不使用scanf 和 printf !!!
3.1 使用上的差异
1 ) scanf 和 printf 不能自动识别输入数据的类型 , 需要手动指定格式字符串 , 容易出现格式错误 。使用时候 需要确保 格式字符串和变量类型匹配 , 否则会出现未定义行为。
2 )cin 和 cout 会根据变量类型自动处理输入输出 , 避免格式化错误 。 相对scanf 和 printf,C++ 会更加易用。
3 ) scanf 和 printf : 格式化输出更加精确直观 , 非常适合复杂格式的输入输出 , 比如需要特定的格式化输出的时候 。
#include <iostream> #include <cstdio> using namespace std; int main() { float a = 3.50; double d = 16.50; cout << "cout: " <<a << " "<< d <<endl; printf("printf: %f %lf\n", a, d); return 0; }
复制
3.2 性能差异
案例演示
结论 : scanf 和 printf 通常比cin 和 cout 快
案例一:数字游戏
使用cin / cout :
#include <iostream> #include <cstdio> #include <string> #include <cmath> using namespace std; int t, x; int main() { cin >> t; while (t--) { cin >> x; int ret = 0; while (x) { int count = 0, high = 0; int tmp = x; while (tmp) { //计算最右边的1代表的值 int low = tmp & -tmp; //如果low中剩余的1就是最后一个1 //就是最左边的1 if (tmp == low) { high = low; } //去掉最右边的1 tmp -= low; count++; } if (count % 2 == 0) { x -= high; } else { x ^= 1; } ret++; } cout << ret << endl; } return 0; }
复制
使用scanf / printf :
#include <iostream> #include <cstdio> #include <string> #include <cmath> using namespace std; int t, x; int main() { scanf("%d", &t); while (t--) { scanf("%d", &x); int ret = 0; while (x) { int count = 0, high = 0; int tmp = x; while (tmp) { //计算最右边的1代表的值 int low = tmp & -tmp; //如果low中剩余的1就是最后一个1 //就是最左边的1 if (tmp == low) { high = low; } //去掉最右边的1 tmp -= low; count++; } if (count % 2 == 0) { x -= high; } else { x ^= 1; } ret++; } printf("%d\n", ret); } return 0; }
复制
案例二:求第 k 小的数
P1923 【深基9.例4】求第 k 小的数 - 洛谷
使用cin / cout :
#include <iostream> #include <cstdio> #include <string> #include <algorithm> using namespace std; const int N = 5000010; int arr[N]; int main() { int n, k; cin >> n >> k; for (int i = 0; i < n; i++) { cin >> arr[i]; } sort(arr, arr + n); cout << arr[k] << endl; return 0; }
复制
使用scanf / printf :
#include <iostream> #include <cstdio> #include <string> #include <algorithm> using namespace std; const int N = 5000010; int arr[N]; int main() { int n, k; cin >> n >> k; for (int i = 0; i < n; i++) { scanf("%d", &arr[i]); } sort(arr, arr + n); cout << arr[k] << endl; return 0; }
复制
上面两个案例中,输入的数据量都比较大,在输入数据的时候如果使用 cin ,都会出现超时的问题,但是换成是 scanf 的方式就能正确的通过。这就是因为两者性能上的差异导致的。
优化方式:
ios::sync_with_stdio(false); // 取消C风格I/O的同步
cin.tie(0); // 解除cin与cout的绑定
总结一下其实就是两个点:
1. C++中为了支持混合使用 cin/cout 和 scanf/printf ,C++ 标准库默认会将 cin 、 cout
等 C++ 流对象与 stdin 、 stdout 等 C 标准库的流对象同步在⼀起。 这种同步操作意味着次