该篇笔记整理C++的一些常用用法和技巧等等,方便查看。
包括所有的资料整理都在最后,统一在这一个文档方便查看。
C++中将字符转换为整数、整数转为字符
将单个字符进行转换,可以直接使用类型转换,或者使用ascii码
如下所示:
int main()
{
char c = '1';
int a = (int) c;
int b = c - 48; # '0'的ascii码为48
int b = c - '0';
}
将数字转为字符可以用char,例如(char)(1 + 'A')
C++ 中将字符串转换为整数
C++是一种强类型语言,不能直接使用类型转换将字符串转为数字,例如下面的方式就会报错:
int main()
{
string str = "7";
int num;
num = (int) str;
}
如果是一个字母字符例如’A’,则转为数字为 ch - 'A' + 10;
使用stoi()函数
接收一个字符串作为输入,并返回其整数版本作为输出
例如:
int main()
{
string str = "7";
int num = stoi(str);
cout << num << endl; # 7
}
最小公倍数、最大公因数、互质判断
最小公倍数是数论中的一个概念,在所有正的公倍数中,最小的公倍数就叫最小公倍数。lcm是英语last common multiple的首字母缩写。
两个整数的lcm与最大公因数之间的关系为:
l c m ( a , b ) = ∣ a b ∣ g c d ( a , b ) lcm(a,b) = \frac{|a b|}{gcd(a,b)} lcm(a,b)=gcd(a,b)∣ab∣
最大公因数(highest common factor)可以利用短除法得到,也称最大公约数,greatest common divisor,gcd。指能够整除多个整数的最大正整数。
求取两个整数最大公约数的方法:
- 列举法,
- 素因数分解,
- 短除法:两数除以其共同素因数,直到两数互素,所有除数的乘积即为最大公约数。
使用短除法,辗转相除法进行代码实现:gcd(a,b) = gcd(b, a%b),不断地用大数除小数,直到除后的余数为0,此时另一个数就是最大公因数。
int gcd(int x, int y){
int z = y;
while(x%y){
z = x%y;
x = y;
y = z;
}
return z;
}
或者:
int gcd(int a, int b){
while (a&&b){
if (a>b) a%=b;
else b%=a;
}
return a + b;
}
使用三元运算符进一步简化:
int gcd(int a, int b){
while(a && b && (a > b ? a%=b : b%=a));
return a+b;
}
然后就可以利用最大公约数求出最小公倍数,
int lcm(a, b){
return a/gcd(a,b) *b;
}
也可以利用最大公约数判断两个整数是否互质,只需判断他们的gcd是否为1,为1则是互质的。
或者使用STL内置函数__gcd(x,y)
求gcd。包含在头文件#include<algorithm>
。
c++中统计字符串中某个字符出现的次数
可以使用count方法
int main()
{
string s = "ababc";
int num = count(s.begin(), s.end(), 'a');
}
c++中创建键值对类型
例如题目:大石头的搬运工
对于键值对类型数据,键可能有重复的,可以直接创建pair类进行模拟,还方便使用。注意这些技巧的运用。
一维前缀和、二维前缀和
一维前缀和:
prefix[i] = prefix[i-1] + a[i];
// 求某个区间的和
prefix[r] - prefix[l-1];
// 恢复
a[i] = prefix[i] - prefix[i-1];
二维前缀和:
pre[i][j] = pre[i][j-1] + pre[i-1][j] -pre[i-1][j-1] + pre[i][j];
// 求某个区间和
一维差分、二维差分
一维的差分:
diff[i] = a[i] - a[i-1];
// 区间操作
diff[l] += c;
diff[r+1] -= c;
// 求原数组
a[i] = a[i-1] + diff[i];
二维的差分:
s[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1];
// 区间操作
s[x1][y1] += c;
s[x1][y2+1] -= c;
s[x2+1][y1] -= c;
s[x2+1][y2+1] += c;
// 恢复
a[i][j] = a[i-1][j] + a[i][j-1] - a[i-1][j-1] + s[i][j];
C++输入二维矩阵
- 使用for循环嵌套输入二维矩阵
int mx[3][3];
// 输入
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 3; ++j){
cin >> mx[i][j];
}
}
// 使用for 循环进行输出
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 3; ++j){
cout << mx[i][j] << " ";
}
}
cout << endl;
- 使用指针输入二维矩阵
int **mx; // 定义指针矩阵
// 分配内存
mx = new int *[3];
for (int i = 0; i < 3; ++i){
mx[i] = new int [3];
}
// 输入
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 3; ++j){
cin >> *(*(mx + i) + j);
}
}
// 输出
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 3; ++j){
cout << *(*(mx + i) + j) << " ";
}
cout << endl;
}
// 释放内存
for (int i = 0; i < 3; ++i){
delete[] mx[i];
}
delete[] mx;
C++中数组求和
使用C++中的numeric库执行数值操作,、
假设一个数组,可以使用accumulate(param1, param2, 0)
求和。
例如:
#include <iostream>
#include <numeric>
using namespace std;
int main()
{
int a[10];
int n = 5;
for (int i = 0; i < n; ++i) cin >> a[i];
int sum = accumulate(a, a+n, 0);
cout << sum << endl;
return 0;
}
当然也可以直接遍历求和。
C++中求最值
max()和min()只能对两个元素求最值?是吗
如果对数组求最值可以使用max_element()或者min_element,注意这两个函数返回的是位置指针,所以要得到值可以用*max_element(a+1, a + 1 +n)。
C++中求区间最值
了解ST表,利用倍增和动态规划的思想实现求区间最值,
在第7章基础数据结构有介绍到,
单调队列求区间最值
给定区间长度求滑动区间的最值,可以理解为滑动窗口最大值算法,
C++优先队列
常用用法:
- pq.pop()
- pq.push()
- pq.top()
- pq.empty()
- pq.size()
默认排序大小,从大到小
priority_queue<int> pq;
pq.push(x);
如果小顶堆,则为
priority_queue<int, vector<int>, greater<int>> pq;
C++中对字符串的操作
对字符串排序
例如:
string s;
cin >> s;
sort(s.begin(), s.end()); // 这样即可
提取子串
例如:
string s; cin >> s;
s2 = s.substr(3,4); // 两个参数,第一个位置起始位置,第二个为长度
C++中lower_bound()和upper_bound()
两个都是利用二分查找的方法在一个排好序的数组中进行查找的。
lower_bound(begin(), end(), num)
,查找第一个大于或等于num的数字,并返回地址,不存在则返回end
upper_bound()
查找第一个大于num的数字
在从大到小的数组中,重载lower_bound()和upper_bound()
lower_bound(begin(), end(), greater<type>())
,二分查找第一个小于或等于num的数字
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000+10;
const int INF = 2*int(1e9) + 10;
#define LL long long
int cmd(int a, int b){
return a > b;
}
int main()
{
int num[6] = {1, 2, 4, 8, 21, 92};
sort(num, num + 6);
int pos1 = lower_bound(num, num+6, 8) - num;
int pos2 = upper_bound(num, num + 6, 8) - num;
cout << pos1 << " " << num[pos1] << '\n';
cout << pos2 << " " << num[pos2] << '\n';
return 0;
}
C++中向上取整、向下取整、四舍五入的小技巧
向上取整,可以用函数ceil()
,还有一种方法就是,假如要对a/b向上取整,例如acwing中的例题“小苹果”,则向上取整的结果是(a+b-1)/b
向下取整,可以用函数floor()
,还有一种方法就是,假如要对a/b向下取整,则为a/b
小数点四舍五入得到整数,可以用(a+b/2)/b
,或者round(a/b)
。
但是如果保留几位小数则需要以下方法,例如保留2位小数:
float a = 2.3678;
cout << round(a*100) / 100 << endl;
cout << floor(a*100 + 0.5) / 100 << endl;
C++中整除的性质
整除了解即余数为0.
掌握k进制转10进制,10进制转k进制
C++中memset函数用法
memset,char型初始化函数
头文件:<string.h> 或<memory.h>
函数原型:
void *memset(void *s, int chm size_t n)
memset(结构体/数组名, 用于替换的ASCII码, 前n个字符)
memset(结构体/数组名, 用于替换的字符, 前n个字符)
将s中的前n个字节用ch替换并返回s
常用于较大的对结构体和数组的清零操作。
可用于将数组初始化为0或-1.
例如:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
int a[10];
memset(a, 0, sizeof(a));
for (int i = 0; i < 10; ++i)cout << a[i] << " ";
cout << endl;
memset(a, -1, sizeof(a));
for (int i = 0; i < 10; ++i) cout << a[i] << " ";
return 0;
}
输出
0 0 0 0 0 0 0 0 0 0
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
Pair用法、在vector中使用Pair
pair组合两个数据,可以是不同类型。
例如STL中的map就是将key和value组合在一起。
或者当某个函数需要返回2个数据的时候,可以选择pair。
pair的实现是一个结构体,访问方式是.first和.second。
头文件#include< utilit >
下面是示例:
pair<T1, T2> p1; // 空的pair对象
pair<T1, T2> p1(v1, v2);
make_pair(v1, v2); // 创建一个新的pair对象
p1 < p2; // 按照字典序比较
pair<string, vector<int>> line; // 两个对象不必相同
使用vector存储pari数据类型
vector<pair<int, string>> myVector;
myVector.push_back(make_pair(1, "Hello"));
for (auto & item : myVector){
cout << item.fisrt << " " << item.second << endl;
}
#include <bits/stdc++.h>
using namespace std;
vector<pair<int, int> > ab;
int main()
{
int n; cin >> n;
int cnt = n/10;
for (int i = 0; i < n; ++i){
int a, b;
cin >> a >> b;
ab.push_back(make_pair(a, b));
}
for (auto & item : ab){
cout << item.first << " " << item.second << endl;
}
return 0;
}
1-N中与N互质的个数有一个公式:欧拉函数模板
例题:蓝桥杯互质数的个数、acwing欧拉函数
https://www.acwing.com/solution/content/81875/
https://www.lanqiao.cn/problems/4330/learning/?page=1&first_category_id=1&name=%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
while (n--){
int a;
cin >> a;
int res = a;
// 分解质因数
for (int i = 2; i <= a/i; ++i){
if (a%i == 0){
// res = res *(1 - 1/i);
res = res / i *(i-1);
while (a % i == 0) a /= i;
}
}
if ( a > 1) res = res / a *(a - 1);
cout << res << endl;
}
return 0;
}
vector,list, map, set的反向遍历技巧
https://articles.oyoung.cc/2020/09/24/C-%E5%B0%8F%E6%8A%80%E5%B7%A7-%E9%9B%86%E5%90%88-vector-list-map-set-%E7%9A%84%E5%8F%8D%E5%90%91%E9%81%8D%E5%8E%86/
可以多看看acwing上的帖子,https://www.acwing.com/blog/content/32956/
C++中优先队列的实现
参考:https://blog.csdn.net/weixin_57761086/article/details/126802156?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170869912916800188573407%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=170869912916800188573407&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-126802156-null-null.142v99pc_search_result_base6&utm_term=c%2B%2B%E4%BC%98%E5%85%88%E9%98%9F%E5%88%97&spm=1018.2226.3001.4187
优先队列默认是大堆。
声明:
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type>>
- T 存储元素的类型
- 第二个是底层使用的存储结构,默认使用vector
- 第三个是优先队列中元素比较方式的类
// 简化版创建默认大堆
priority_queue<int> q;
// 完整版
priority_queue<int, vector<int>, less<int>> q;
// 创建小堆
priority_queue<int, vector<int>, greater<int>> q;
C++中vector容器的排序或者数组的排序
从小到大:sort(arr.begin(), arr.end())
从大到小:
sort<arr.begin(), arr.end(), greater<int>()>
- 使用自定义函数
bool cmp_max(int x, int y){
return x > y;
}
sort(arr.begin(), arr.end(), cmp_max);
当然了这里cmp_max的写法也可以这样写:
sort(arr.begin(), arr.end(), [&](int x, int y){
return x > y;
}
- 先sort(),再reverse()
sort(arr.begin(), arr.end());
reverse(arr.begin(), arr.end());
数组的排序:
int a[10];
sort(a+1, a+a.size());
C++中vector容器删除元素
示例:
vector<int> v = {1, 2, 3, 4, 5, 6};
v.erase(v.begin() + 2);
C++中数组或者vector获取最大值、最小值以及索引
示例:
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 数组获取
int arr[6] = {1, 2, 3, 4, 5, 6};
int maxValue = *max_element(arr, arr+sizeof(arr)/sizeof(int));
int minValue = *min_element(arr, arr+sizeof(arr)/sizeof(int));
int maxPosition = max_element(arr, arr+6) - arr;
int minPosition = min_element(arr, arr+6) - arr;
cout << "maxValue: " << maxValue << endl;
cout << "minValue: " << minValue << endl;
cout << "maxPosition: " << maxPosition << endl;
cout << "minPosition: " << minPosition << endl;
// vector获取
vector<int> arr1{1,2,3,4,5,6};
int maxValue1 = *max_element(arr1.begin(), arr1.end());
int minValue1 = *min_element(arr1.begin(), arr1.end());
int maxPosition1 = max_element(arr1.begin(), arr1.end()) - arr1.begin();
int minPosition1 = min_element(arr1.begin(), arr1.end()) - arr1.begin();
cout << "maxValue1: " << maxValue1 << endl;
cout << "minValue1: " << minValue1 << endl;
cout << "maxPosition1: " << maxPosition1 << endl;
cout << "minPosition1: " << minPosition1 << endl;
}
C和C++中int a;默认值为多少
C语言中定义int变量,全局变量即定义在函数外的变量,默认为0;
静态局部变量默认为0;
C++也是。
欧拉函数模板
4330欧拉函模板,
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a; cin >> a;
int res = a;
// 分解质因数
for (int i = 2; i <= a/i; ++i){
if(a%i == 0){
res = res / i * (i -1);
while(a%i == 0) a /= i;
}
}
if (a > 1) res = res / a*(a - 1);
cout << res << endl;
return 0;
}
快速幂模板
LL ksm(LL a, LL b){
LL res = 1;
while(b){
if (b & 1) res = res*a % MOD;
a = a*a%MOD;
b>>=1;
}
return res;
}
C++中求log对数运算
默认的log函数,
#include <iostream>
#include <cmath>
using namespace std;
int main(){
double a = 9, b = 10;
cout << log(a) << endl; // log默认以e为底
cout << log(exp(a)) << endl;
cout << log10(b) << endl; // 以10为底
return 0;
}
自定义m为底, 求logm(n)的值,可以如下:求以2为底可以用到
double a = log(n)/ log(m);
C++中的绝对值
不同类型使用不同的绝对值函数,
int abs(int i); // 整型
double cabs(struct complex znum); // 复数的绝对值
double fabs(double x); // 双精度的绝对值
long labs(long n); // 长整型的绝对值
C++中对字符串求长度、截取字符串
可以使用三种范式:
string strTest = "test";
// 第一种
strTest.length();
// 第二种
strTest.size();
// 第三种,转换为c风格字符串
strlen(strTest.c_str());
https://blog.csdn.net/ezhou_liukai/article/details/13779091
c++STL中Map的按Key排序和按Value排序
map内部本身就是按序存储的,例如红黑树,插入数据时会按照key的大小顺序进行存储。
插入数据可以如下:
map<int, int> mymap;
mymap[0] = 0; // 方式1
mymap.insert(make_pair(1,1)); // 方式2
使用.count(key)查看是否存在key
使用.keys获取所有的key
使用.first和.second访问键值。