12月主要学习了c++中stl相关知识
空余时间学习了些基础算法
STL
1.容器
string容器
第一次学到这玩意感觉强的一比啊,做一些字符串的题感觉比c的char方便了不少。
这是学长课堂算法方向第六次课中的第一题,用string做的(主要是string类进行字符串比较直接== 就行了不用strcmp)。
除了直接使用==,!=等关系运算符进行string类字符串的比较,还可以用+=来进行字符串的拼接。
string s="ab";
s+='c';
这样s将由"ab"变为"abc"。
当时的第二道题。(虽然这道题只过了63%的测试用例 )代码中用到了string类的两个函数,一个是.size(),作用与c的strlen()相似,但是使用方法不同
代码中还用到了string& assign(const string &s, int start, int n);
意思是将s从start开始n个字符赋值给字符串.
使用string类读入一行字符串(包括空格),遇回车结束
int n;
string s;
cin >> n;
getchar(); //cin.get()
getline(cin, s);//可正确读入下一行的输入
Vector容器
vector为可变长数组(动态数组),定义的vector数组可以随时添加数值和删除元素。
头文件#include <vector>
使用vector定义一个数组与平常c语言中定义数组的方式不一样
vector<int> a; //定义一个名为a的一维数组,数组存储int类型数据
vector<double> b;//定义一个名为b的一维数组,数组存储double类型数据
vector<int> a{1, 2, 3, 4, 5};
vector<int> v[5];//定义二维vector数组
vector<vector<int>> v;//定义一个行和列均可变的二维数组
在vector容器中常用的一些函数
c.front();//返回第一个数据
c.back();//返回数组中的最后一个数据
c.push_back();//在尾部加一个数据
c.size();//返回实际数据个数
c.clear();//清楚所有元素
c.begin();//返回首元素的迭代器
c.end();//返回最后一个元素**后一个位置**的迭代器
c.insert(it, x);//向任意迭代器it插入一个元素x
例:c.insert(c.begin() + 2,-1);//将-1插入c[2]的位置
用迭代器访问vector数组
vector<int> vi;
vector<int>::iterator it = vi.begin();//迭代器it指向vi第一个元素(可以auto it=vi.begin())
for(; it != vi.end();it ++)
cout << *it << " ";//遍历vi中所有元素
智能指针遍历vector数组
vector<int> a(n);
for (auto &x: a) {
cin >> x; // 进行输入
for(auto val : v) {
cout << val << " "; // 进行输出
其他的容器如queue,map等还没具体使用做过题,暂且不写。
函数
sort排序
时间复杂度是:O(NlogN),说是快速排序和归并排序的结合体。
int a[N]; //
sort(a , a + n); 对 a 数组的[0, n]位置进行从小到大排序
sort(a, a + n, greater<int>());//从大到小
vector<int> b(n + 1); // vector数组定义
sort(b.begin() + 1, b.end());
sort(b.begin() + 1, b.end(), greater<int>()); // 降序
reverse
将序列翻转
string s = "abcde";
reverse(s.begin(), s.end());//对s进行翻转
cout << s << '\n';//edcba
int a[] = {1, 2, 3, 4};
reverse(a, a + 4);//对a数组进行翻转
cout << a[0] << a[1] << a[2] << a[3];//4321
算法学习
在看acwing基础算法课
目前只学了快排,归并排序,高精度加减乘除,二分,前缀和,差分,双指针,位运算 (有点没懂)主要讲讲二分。
整数二分算法模板
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
这是二分常见两种模版,第一种没啥好说的,主要是第二种,由于c语言在做除法时是向下取整,在计算mid的时候要+1,不然可能会出现边界问题造成死循环。
洛谷上的一道二分题(提交了得有10多次才过,要不就全wa要不就全tle),开始我的思路是先将树的高度排序,以最矮的作为l最高的作为r进行二分,遍历每棵树的高度-mid,如果大于0就加入sum,当sumM的时候直接return 0,但是属于是没认真读题了,说是至少为M米,就是说测试数据不是刚好能summid的。后面一句提醒了如果再升高1米,将得不到M米木材,于是我就又定义了一个mid2=mid+1,当sum2和sum同时满足条件时候返回mid。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
long long n, m, i, tmp, sum = 0, sum2=0;
cin >> n >> m;
long long * s = new long long[n];
for (i = 0; i < n; i++) cin >> s[i];
sort(s, s + n);
int l = s[0], r = s[n - 1], mid = (l + r) / 2,mid2=mid+1;
while (l < r)
{
for (i = 0; i < n; i++)
{
if (s[i] - mid >= 0) sum += s[i] - mid;
if (s[i] - mid2 >= 0) sum2 += s[i] - mid2;
}
if (sum >= m&&sum2<m)
{
cout << mid;
return 0;
}
else
{
if (sum < m) r = mid;
else l = mid + 1;
mid = (l + r) / 2;
mid2 = mid + 1;
sum = 0;
sum2 = 0;
}
}
return 0;
}