ACM模式输入输出攻略 | C++篇

6 篇文章 1 订阅
5 篇文章 0 订阅


ACM模式输入输出攻略 | C++篇

大家好,这里是小黛~

三月开始,就会陆续开启各大公司暑期实习的笔试和面试,而笔试中,ACM模式是必须要去熟练掌握的,今天就来针对ACM模式进行详细介绍。

这个系列首先以C++为例,进行ACM模式的讲解,后续会补齐JAVA、GO、JS等常用语言的输入输出案例。

本文主要介绍五个方面:

第一是介绍核心代码模式ACM模式,以及笔试面试的常见场景。

第二是介绍**C++**中常用的输入输出函数

第三是以笔试面试中常见的输入为例,进行代码层面案例介绍

第四是给出一些练习ACM模式的平台

第五是把常见的数据结构定义,输入和输出展示出来,主要是链表和二叉树。

1.核心代码模式与ACM模式

当我们刷算法题的时候,比如力扣、牛客这些网站,很多的题目只需要我们写出函数体(核心代码),平台就可以自动帮助我们补齐输入输出,进行调试,但,在笔试和面试中,往往需要自己写出可以运行的完整代码(ACM模式),这个时候,需要我们去了解一下自己所使用的语言下的输入输出如何去设计。

首先给出几个注意事项:

1.笔试平台用的比较多的,比如牛客,赛码,可以提前去熟悉熟悉上面的操作。

2.有些笔试,需要自己写输入输出,有些,则不需要,但我们必须要把输入输出搞懂,这样就不怕是什么类型的笔试了,而且输入输出本身是不难的,学习一下就可以完全掌握。最好不要出现,算法题的核心思路会写,卡在了输入输出上,这样就很难受了。

3.有些笔试,还会让大伙自己设计测试用例,这个平时练习的时候也可以注意一下,主要核心的思想就是测试用例设计的几个原则。

4.不仅仅是笔试,有些面试,也会要求你写输入输出测试用例

面试手撕代码的几种形式:

1.平台类

去面试官给定的平台上去面试,上面可以编写代码,调试和运行,这些平台有的写好了函数框架,有的是白板,需要自己写全部内容

2.自己的IDE

面试官要求候选人打开自己的ide,并共享桌面进行编写,这种肯定是要自己写全输入输出了

3.要求补齐测试用例

有些面试官,比如微软的面试官,可能会让你写完代码后,自己设计尽可能全面的测试用例,对你编写的代码进行测试。

2.C++常用的输入输出方法

C++的输入输出有很多种方式,既有继承自C语言的,也有其自己独特的。这里呢,不会把全部输入输出函数进行罗列,只会介绍几个在笔试面试中经常被用到的,我认为,掌握这几个足够了,如果有余力,可以去官方文档查看更多关于输入输出的函数进行深度学习。

2.1 输入

首先,在C++语言中,要使用标准的输入,需要包含头文件<iostream>

(1)cin

cin是C++中, 标准的输入流对象,下面列出cin的两个用法,单独读入,和批量读入

cin的原理,简单来讲,是有一个缓冲区,我们键盘输入的数据,会先存到缓冲区中,用cin可以从缓冲区中读取数据。

注意1:cin可以连续从键盘读入数据

注意2:cin以空格、tab、换行符作为分隔符

注意3:cin从第一个非空格字符开始读取,直到遇到分隔符结束读取

示例:

// 用法1,读入单数据
int num;
cin >> num;
cout << num << endl;  // 输出读入的整数num

// 用法2,批量读入多个数据
vector<int> nums(5);
for(int i = 0; i < nums.size(); i++) {
	cin >> nums[i];
}
// 输出读入的数组
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}
(2)getline()

从cin的注意中,也可以看出,当我们要求读取的字符串中间存在空格的时候,cin会读取不全整个字符串,这个时候,可以采用getline()函数来解决。

注意1:使用getline()函数的时候,需要包含头文件<string>

注意2:getline()函数会读取一行,读取的字符串包括空格,遇到换行符结束

示例:

string s;
getline(cin, s);
// 输出读入的字符串
cout << s << endl;
(3)getchar()

该函数会从缓存区中读出一个字符,经常被用于判断是否换行

示例:

char ch;
ch = getchar();
// 输出读入的字符
cout << ch << endl;

2.2 输出

同样的,在C++语言中,要使用标准的输出,也需要包含头文件<iostream>

输出这边,主要介绍一个函数,就是用的最多的cout,需要注意的是,如果输出endl对象的时候,会输出一个换行符,类似\n

示例:

string s = "hello, Irray~";
// 看看二者有何不同
cout << "hello, Irray~";
cout << s << endl;

当然,C++中的输入输出函数不止这几个,其他的输入函数包括scanf()cin.get()等等方式,输出函数也有printf()clogcerr等方式,要根据具体的使用场景,选择具体的输入输出函数。

但,接下来的案例中,掌握上述三个方法是足够的。不想介绍太多,也是因为,记忆太多方法,容易记混,不如用最简洁的方式实现全部问题。

3.案例

(1)一维数组

此类输入,每个元素为一个int或者char,有两类常见的案例:

1.固定数目
输入格式:
3
1 2 3

or

3 1 2 3
解析:

对于第一组,第一行的3为整数的个数,第二行为三个用空格隔开的整数,因此可以采用cin来进行读取

对于第二组,第一行的3为整数的个数,空格后面的数据为三个用空格隔开的整数,因此可以采用cin来进行读取

此类问题,可以先创建一个vector<int>,大小设置为给定值,然后通过for循环来循环输入

答案:
int n;
cin >> n; // 读入3,说明数组的大小是3
vector<int> nums(n); // 创建大小为3的vector<int>
for(int i = 0; i < n; i++) {
	cin >> nums[i];
}

// 验证是否读入成功
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}
cout << endl;
2.不固定数目
输入格式:
1 2 3 4
解析:

输入的数据为四个用空格间隔的整数,没有指定整数个数,因此可以用while循环结合cin来处理该问题。

答案:
vector<int> nums;
int num;
while(cin >> num) {
	nums.push_back(num);
	// 读到换行符,终止循环
	if(getchar() == '\n') {
		break;
	}
}

// 验证是否读入成功
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}
cout << endl;

(2)二维数组

除了一维数组这种最基础的输入外,还会考察二维数组的输入,尤其是在dfs、dp类型的题目中。

二维数组主要有两种方式:

1.常规模式
输入格式:
2 3
1 2 3
1 2 3
解析:

第一行的2,代表数据为2行,3代表数据为3列,因此根据第一行,可以得出,所输入数据为2行3列的二维数组。接下来的6个数字,就是按照空格和换行符分隔开的2x3二维数组,因此用for循环和cin即可处理

答案:
int m; // 接收行数
int n; // 接收列数

cin >> m >> n;

vector<vector<int>> matrix(m, vector<int>(n));

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

// 验证是否读入成功
for(int i = 0; i < m; i++) {
	for(int j = 0; j < n; j++) {
		cout << matrix[i][j] << " ";
	}
	cout << endl;
}
2.每一行数据是逗号隔开的整数
输入格式:
2 3
1,2,3
1,2,3
解析:

第一行的2,代表数据为2行,3代表数据为3列,因此根据第一行,可以得出,所输入数据为2行3列的二维数组。接下来的2行,分别是一个字符串,字符串中用逗号隔开每个整数。这里采用读入字符串的方式,并将读入的字符串进行按逗号分开。

答案:
int m; // 接收行数
int n; // 接收列数

cin >> m >> n;

vector<vector<int>> matrix(m);

for(int i = 0; i < m; i++) {
    // 读入字符串
	string s;
	getline(cin, s);
	
	// 将读入的字符串按照逗号分隔为vector<int>
	vector<int> vec;
	int p = 0;
	for(int q = 0; q < s.size(); q++) {
		p = q;
		while(s[p] != ',' && p < s.size()) {
			p++;
		}
		string tmp = s.substr(q, p - q);
		vec.push_back(stoi(tmp));
		q = p;
	}
	
	//写入matrix
	matrix[i] = vec;
	vec.clear();
}

// 验证是否读入成功
for(int i = 0; i < matrix.size(); i++) {
	for(int j = 0; j < matrix[i].size(); j++) {
		cout << matrix[i][j] << " ";
	}
	cout << endl;
}

(3)字符串

1.单字符串
输入格式:
abc
解析:

cin读入即可

答案:
string s;
cin >> s;

// 验证是否读入成功
cout << s << endl;
2.给定数目多字符串
输入格式:
3 abc ab a
解析:

第一行的3,代表有3个字符串,后续为用空格隔开的3个字符串,采用for循环和cin读入即可

答案:
int n;
cin >> n; // 读入3,说明字符串数组的大小是3
vector<string> strings(n); // 创建大小为3的vector<string>
for(int i = 0; i < n; i++) {
	cin >> strings[i];
}

// 验证是否读入成功
for(int i = 0; i < strings.size(); i++) {
	cout << strings[i] << " ";
}
cout << endl;
3.不给定数目多字符串
输入格式:
abc ab a d
解析:

输入为用空格隔开的若干个字符串。

答案:
vector<string> strings;
string str;
while(cin >> str) {
	strings.push_back(str);
	// 读到换行符,终止循环
	if(getchar() == '\n') {
		break;
	}
}

// 验证是否读入成功
for(int i = 0; i < strings.size(); i++) {
	cout << strings[i] << " ";
}
cout << endl;
4.字符串转整数数组
输入格式:
11,22,3,4
解析:

输入为一个完整字符串,字符串内容是按照逗号隔开的一个数组,可以先读入完成字符串,然后根据逗号进行分隔

答案:
vector<int> vec;

// 读入字符串
string s;
getline(cin, s);

// 将读入的字符串按照逗号分隔为vector<int>
	int p = 0;
	for(int q = 0; q < s.size(); q++) {
		p = q;
		while(s[p] != ',' && p < s.size()) {
			p++;
		}
		string tmp = s.substr(q, p - q);
		vec.push_back(stoi(tmp));
		q = p;
	}

// 验证是否读入成功
for(int i = 0; i < vec.size(); i++) {
	cout << vec[i] << " ";
}
cout << endl;

4.ACM模式练习平台

除了在笔试中实战之外,也可以在牛客平台进行练习:https://ac.nowcoder.com/acm/contest/5652

同时,牛客上也有很多专门的ACM模式算法题。

这里给出一个案例:

题目来源:https://ac.nowcoder.com/acm/contest/5652/A

**输入:**输入包括两个正整数a,b(1 <= a, b <= 1000),输入数据包括多组。

**输出:**输出a+b的结果

示例:

1)输入

1 5
10 20

2)输出

6
30

解答:

因为比较简单,就直接给出代码了。

#include <iostream>
using namespace std;

int main() {
    int a;
    int b;
    while(cin >> a >> b) {
        cout << a + b << endl;
    }
    
    return 0;
}

5.常见数据结构定义

在ACM模式中,链表、二叉树这些数据结构的定义也需要自己去定义,接下来就给出二者的定义、输入和输出。

这里就直接给出代码了,想必大伙对数据结构都是了如指掌的。

1.链表

#include <iostream>
using namespace std;

// 链表定义,并给出两个有参构造函数
struct ListNode
{
    int val;
    ListNode* next;
    ListNode(int _val):val(_val),next(nullptr){}
    ListNode(int _val,ListNode* _next):val(_val),next(_next){}
};

int main()
{

	// 根据控制台的输入,创建一条单链表
    ListNode* LHead = new ListNode(-1);
    ListNode* pre = LHead;
    ListNode* cur = nullptr;
    
    int num;
    while(cin >> num)
    {
    	// 为了简单起见,设置为-1退出,后续可优化,这里只是给出一个例子
        if(num == -1) break;
        cur = new ListNode(num);
        pre->next = cur;
        pre = cur;
    }
    
    cur = LHead->next;
    
    // 输出单链表的value
    while(cur)
    {
        cout << cur->val << " ";
        cur = cur->next;
    }
    
    cout << endl;
    
    return 0;
}

2.二叉树

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

//定义树节点
struct TreeNode
{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode():val(0),left(nullptr),right(nullptr){}
    TreeNode(int _val):val(_val),left(nullptr),right(nullptr){}
    TreeNode(int _val,TreeNode* _left,TreeNode* _right):val(0),left(_left),right(_right){}
};

//根据数组生成树
TreeNode* buildTree(const vector<int>& v)
{
    vector<TreeNode*> vTree(v.size(),nullptr);
    TreeNode* root = nullptr;
    for(int i = 0; i < v.size(); i++)
    {
        TreeNode* node = nullptr;
        if(v[i] != -1)
        {
            node = new TreeNode(v[i]);
        }
        vTree[i] = node;
    }
    root = vTree[0];
    for(int i = 0; 2 * i + 2 < v.size(); i++)
    {
        if(vTree[i] != nullptr)
        {
            vTree[i]->left = vTree[2 * i + 1];
            vTree[i]->right = vTree[2 * i + 2];
        }
    }
    return root;
}

//根据二叉树根节点层序遍历并打印
void printBinaryTree(TreeNode* root)
{
    if(root == nullptr) return;
    vector<vector<int>> ans;
    queue<TreeNode*> q;
    q.push(root);
    while(!q.empty())
    {
        int size = q.size();
        vector<int> path;
        for(int i = 0;i<size;i++)
        {
            TreeNode* node = q.front();
            q.pop();
            if(node == nullptr)
            {
                path.push_back(-1);
            }
            else
            {
                path.push_back(node->val);
                q.push(node->left);
                q.push(node->right);
            }
        }
        ans.push_back(path);
    }
    
    for(int i = 0;i<ans.size();i++)
    {
        for(int j = 0;j<ans[i].size();j++)
        {
            cout << ans[i][j] << " ";
        }
        cout << endl;
    }
    return;
}

int main()
{
	// 验证
    vector<int> v = {4,1,6,0,2,5,7,-1,-1,-1,3,-1,-1,-1,8};
    TreeNode* root = buildTree(v);
    printBinaryTree(root);
    
    return 0;
}

欸嘿嘿,终于写完了!!!

本文内容干货非常非常多,从笔试面试环境的要点,到C++输入输出的具体函数,再到几乎覆盖全部情况的ACM模式写法,最后也给出了链表和二叉树的定义和输入输出。

全文代码都在本地IDE跑过,也都是本人今天亲手敲出来的,觉得有收获的可以点赞一波。

想和小黛一起交流的,也欢迎私聊,改简历、求职指导、模拟面试都是可以的哈~~~也有小窝,可以加我,我拉你哦

本人23年秋招拿了政策行总行、百度sp,美团,中国银行总行,中国银联总部等25个offer,非常欢迎小伙伴和我交流哇,改简历,学习计划,笔试面试经验,免费免费免费~~想来交流的随时私聊我哈

  • 105
    点赞
  • 353
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值