STL 常用容器类及方法:
一、string
string s1 = "123456";
s1.empty()
s1.size()
s1[i] 返回i位置的字符
s1 == s2
s3 = s1+s2
s3 = s1.substr(i,1) i位置截取1个字符
s4 = s1.substr(1); 从第1个位置截取到最后
int iPos = s1.find("23", 0); 查找字符或字符串出现的位置,查找不到返回-1
find_first_of("23",0) 查找第一个出现的位置
find_last_of 查找最后一个出现的位置
subs.erase(0,1); 在0位置删除1个元素
字符串替换,将line替换为空格
strrow.replace(strrow.begin(), strrow.begin() + strlen("line"), "");
strcol.replace(strcol.begin(), strcol.begin() + strlen("col"), "");
string转int:stoi
int转string: to_string
//分割字符串
vector<string> mySolution::split(string str)
{
vector<string> res;
istringstream s_in(str); //#include <sstream>
string c;
while (getline(s_in, c, ',')) {
cout << c << endl;
res.push_back(c);
}
return res;
}
isalpha(char c)//判断是否为字母 isdigit(char c)//判断是否为数字 isalnum(char c)//判断是否为数字或字母
tolower(char c)//变成小写字母 toupper(char c)//变成大写字母
lower_bound()
用于在指定区域内(左闭右开)查找不小于目标值的第一个元素,也就是说最终查找的不一定是和目标值相等的元素,也可能是比目标值大的元素。其底层实现是二分查找。
upper_bound()
在指定目标区域中查找大于目标值的第一个元素,返回该元素所在位置的迭代器。
int main() {
vector<int>nums{ 1,2,3,5,5 };
auto it1 = lower_bound(nums.begin(), nums.end(), 3); //查找大于等于3的元素
cout << *it1<< endl;
auto it2 = lower_bound(nums.begin(), nums.end(), 4); //查找大于等于4的元素
cout << *it2 << endl;
system("pause");
return 0;
} 》》 3 5
swap 成员函数可以交换两个 string 对象的内容。
if ((n = s1.find('u')) != string::npos) //查找 u 出现的位置
cout << "1) " << n << ", " << s1.substr(n) << endl;
//输出 l)2,urce Code
str1.find(str2,5); // 从str1的第5个字符开始查找str2
find_first_of 函数最容易出错的地方是和find函数搞混。它最大的区别就是如果在一个字符串str1中查找另一个字符串str2,如果str1中含有str2中的任何字符,则就会查找成功,而find则不同;
string str1("I am change");
string str2("about");
int k=str1.find_first_of(str2); //k返回的值是about这5个字符中任何一个首次在str1中出现的位置;
find() 可以在指定字符串中查找完全匹配子串的位置
find_first_of() 在指定字符串中查找第一个任意匹配子串中字符的位置
find_first_not_of() 在指定字符串中查找第一个不任意匹配子串中字符的位置
- 在字符串中查找第一个与str中的字符都不匹配的字符,返回它的位置。搜索从index开始。如果没找到就返回string::nops
string str ("look for non-alphabetic characters...");
size_t found;
found=str.find_first_not_of("abcdefghijklmnopqrstuvwxyz ");
if (found!=string::npos)
{
cout << "First non-alphabetic character is " << str[found];
cout << " at position " << int(found) << endl;
}
First non-alphabetic character is - at position 12
int\long\float等转string方法:
to_string
二、vector 向量数组
vector<string> myVec;
初始化:
int a[3] = {4,1,2};
vector<int> nums1(a, a+3);
int b[4] = {1,3,4,2};
vector<int> nums2(b, b+4);
myVec.push_back(s1); 在尾部添加一个数据
myVec.pop_back(); 在尾部删除一个数据
myVec.size() 数组的大小
myVec[i] 输出对应元素
front() 返回头部元素
back() 返回尾部元素
sort(obj.begin(),obj.end());//从小到大
reverse(obj.begin(),obj.end());//从大到小
sort 需要头文件 #include <algorithm>
vector<int> nums(nums1);
nums.insert(nums.end(), nums2.begin(), nums2.end()); // vector 追加,和 append效果一样
如果想 sort 来降序,可重写 sort
bool compare(int a,int b)
{
return a< b; //升序排列,如果改为return a>b,则为降序
}
int a[20]={2,4,1,23,5,76,0,43,24,65},i;
for(i=0;i<20;i++)
cout<< a[i]<< endl;
sort(a,a+20,compare);
static bool abs_compare(int a, int b) { return (std::abs(a) < std::abs(b)); }
std::vector<int> v{ 3, 1, -14, 1, 5, 9 };
std::vector<int>::iterator result;
result = std::max_element(v.begin(), v.end());
std::cout << "max element is: " << *result << '\n';
std::cout << "max element at: " << std::distance(v.begin(), result) << '\n';
result = std::max_element(v.begin(), v.end(), abs_compare);
int num = count(v1.begin(), v1.end(), 1);//算法 count 统计v1中等于1的数的个数
cout << num << endl;
二维数组:vector<vector<int>> input 列数:input[i].size() 或 input[0].size()
初始化方法:
vector<vector<int>> matrix(0,vector<int>(3)); // 先初始化为 0 行 3列,再push_back 插入3行,每行数据使用vector初始化
int a1[] = {1,1,1};
vector<int> vec1(a1,a1+3);
matrix.push_back(vec1);
int a2[] = {1,0,1};
vector<int> vec2(a2,a2+3);
matrix.push_back(vec2);
int a3[] = {1,1,1};
vector<int> vec3(a3,a3+3);
matrix.push_back(vec3)
vector< vector<int>> m(5, vector<int>(6));
for(int i=0; i<m.size(); i++)
{
for(int j=0; j<m[i].size(); j++)
{
m[i][j] = i+j;
}
}
vector<vector<int> >array(3);//二维数组包含3个向量
for(int i = 0; i <3; i++)
array[i].resize(3);//设置数组的大小3X3
//现在你可以和使用数组一样使用这个vector
for (int i = 0; i <3; i++)
for (int j = 0; j <3; j++)
array[i][j] = (i*j);
//输出
for (int i = 0; i <3; i++)
{
for (int j = 0; j <3; j++)
cout<<array[i][j] << " ";
cout<<endl;
}
cout << "------------" << endl;
array.resize(5);//二维数组包含5个向量
array[3].resize(3);//第4个向量包含3个元素
array[4].resize(3);//第5个向量包含3个元素
//现在是5X3的数组了
for (int i = 0; i <5; i++)
for (int j = 0; j <3; j++)
array[i][j] = (i*j);
for (int i = 0; i <5; i++)
{
for (int j = 0; j <3; j++)
cout <<array[i][j] << " ";
cout <<endl;
}
//遍历取值
vector<int>& piles
for (int pile : piles) {}
//逆向遍历
for (vector<int>::reverse_iterator rit = v3.rbegin(); rit != v3.rend(); rit++)
{
cout << *rit << " ";
}
//指定元素删除
//v1.erase(v1.begin());
for (vector<int>::iterator it = v1.begin(); it != v1.end();)
{
if (*it == 2)
{
it = v1.erase(it); //当删除迭代器所指向的元素的时候,erase删除函数会返回下一个元素的指针,让it去接,实现自动下移
}
else
{
it++;
}
}
三、list 双向链表
#include <list>
list<int> lst1; 空链表
lst1.push_back(1) 在list尾部添加一个元素
lst1.push_front(2) 在list头部添加一个元素
lst1.pop_back() 删除最后一个元素
lst1.pop_front() 删除第一个元素
遍历所有元素:
list<int>::iterator i;
for(i=lst1.begin(); i != lst1.end(); i++)
{
cout<<*i;
}
在指定位置插入元素
lst1.insert(i,4);
i 是 list<int>::iterator
在指定位置删除元素
lst1.erase(ipos);
清空列表
lst1.clear() 删除所有元素
lst找不到返回end()
list< int>::iterator itePos = ::find(lst.begin(),lst.end(),5);//在list中寻找值为5的元素位置。
lst.insert(itePos,100);//默认在元素5的前面插入100.
list< int>::iterator itePos = ::find(lst.begin(),lst.end(),1);//在list中寻找值为1的元素位置。
itePos = lst.erase(itePos);//删除元素1,并返回元素1的下一个元素位置。注:迭代器被删除后需要重新赋值。
四、栈 stack
stack<int> s;
s.empty(); //判断stack是否为空,为空返回true,否则返回false
s.size(); //返回stack中元素的个数
s.pop(); //删除栈顶元素,但不返回其值
s.top(); //返回栈顶元素的值,但不删除此元素
s.push(item); //在栈顶压入新元素item
//取stack的栈顶元素top() 前先判断栈的大小 大于0
unordered_map<char,char> map;
if(st.size()>0 && st.top() == map[s[i]]){//(*map.find(s[i])).second){
st.pop();
}
五、队列 queue
queue<int> q; //priority_queue<int> q;
q.empty(); //判断队列是否为空
q.size(); //返回队列长度
q.push(item); //对于queue,在队尾压入一个新元素
//对于priority_queue,在基于优先级的适当位置插入新元素
//queue only:
q.front(); //返回队首元素的值,但不删除该元素
q.back(); //返回队尾元素的值,但不删除该元素
//priority_queue only:
q.top(); //返回具有最高优先级的元素值,但不删除该元素
deque是双端队列
deq.front():返回第一个元素的引用。
deq.back():返回最后一个元素的引用。
deq.push_front(x):把元素x插入到双向队列的头部。
deq.pop_front():弹出双向队列的第一个元素。
deq.push_back(x):把元素x插入到双向队列的尾部。
deq.pop_back():弹出双向队列的最后一个元素。
六、map
map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent.insert(pair<int, string>(2, "student_two"));
mapStudent[3]="student_three"; //简单的赋值方法
mapStudent[4]="student_four";
mapStudent.erase(1); //按照key删除元素
map<int, string>::iterator it = mapStudent.find(1); //返回对应的迭代器
if (it != mapStudent.end())
{
cout<<it->second<<endl; //输出查找到的值
mapStudent.erase (it); //删除查找到的迭代器
}
//遍历map 输出元素
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout<<iter->first<<' '<<iter->second<<endl;
clear() 删除所有元素
6.1 unordered_map 存储key-value的组合
unordered_map初始化:
unordered_map<char,char> map;
map.insert(pair<char,char>(')','('));
map.insert(pair<char,char>(']','['));
map.insert(pair<char,char>('}','{'));
取值:map[s[i]]
如何判断unordered_map 判断某个键是否存在呢?
find函数:存在返回对应迭代器,不存在就返回end
iterator find ( const key_type& key );
cout如果key存在,则count返回1,如果不存在,则count返回0.
size_type count ( const key_type& key ) const
map遍历:
for (auto iter = input.begin(); iter != input.end(); ++iter) {
if (iter->second >= startTime && iter->second <= endTime) {
count++;
}
}
区别总结:
- 内存占有率的问题就转化成红黑树 VS hash表 , 还是
unorder_map占用的内存要高
。 - 但是unordered_map执行效率要比map高很多,看数据量
- 在需要有序性或者对单次查询有时间要求的应用场景下,应使用map,其余情况应使用unordered_map。
排序:
按照value排序:
bool cmp_by_value_less(const PAIR& l,const PAIR& r)
{
return l.second<r.second;
}
vector<PAIR> vec(mapA.begin(),mapA.end());
sort(vec.begin(),vec.end(),cmp_by_value_less);
cout<<endl<<"map:sorted by value(less)"<<endl;
for(int i=0;i<vec.size();i++)
{
cout<<"The price of "<<vec[i].first<<" is $"<<vec[i].second<<endl;
}
按照key排序:
map<string,double,greater<string>> mapB;
七、set
set容器内的元素会被自动排序,set与map不同,set中的元素即是键值又是实值,set不允许两个元素有相同的键值。
由于set元素是排好序的,且默认为升序,因此当set集合中的元素为结构体或自定义类时,该结构体或自定义类必须实现 运算符‘<’的重载。
multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。
set和multiset的底层实现是一种高效的平衡二叉树,即红黑树(Red-Black Tree)。
set<int> s;
s.insert(10);
s.insert(20);
s.insert(30);
for (set<int>::iterator iter = s.begin(); iter != s.end(); ++iter)
{
cout << *iter << " ";
}
八、常用算法
1、n次方:pow(10, n); 10的n次方
2、sort 对vector进行排序
3、数组的排列组合
vector<int> p(k);
for (size_t i=0; i<k; i++) {
p[i] = i;
}
// 循环所有的排列组合
while (next_permutation (p.begin(), p.end())) {
PrintPermutation(p); // 0 2 1; 1 0 2; 1 2 0; 2 0 1; 2 1 0;
// 按照一个排列组合 获取数组
vector<string> nextVec = NextStringVector(vec, p);
int diff = MaxStr(nextVec) - MinStr(nextVec);
if (diff < minDiff) {
minDiff = diff;
}
}
4、判断是否大写字符isupper
按照字符进行大小写转换tolower() toupper()
转换整个string:transform(s.begin(),s.end(),s.begin(),::tolower); 利用transform函数
5、stl中的反转算法reverse
reverse(str.begin(), str.end()); //string使用<algorithm>里的reverse ,string类自身没有reverse成员函数
reverse(vec.begin(), vec.end());
reverse(list.begin(), list.end());
deque<int> myd{ 2,4,6,8 }; reverse(myd.begin(), myd.end());
6、int min = Integer.MAX_VALUE;
min = Math.min(min, k - i + 1);
九、解题思路和套路
1、简单的话进行暴力破解 尝试是否容易解决,如果不行尝试套路。
要选择合适的数据结构,比如map stack queue vector
2、计算一个数组的差值比如:1793. 【认证试题】给定差值的组合
或者 对两个数组进行比较操作的,比如1. 两数之和 (哪两个数的和是某个值)496. 下一个更大元素 (另外一个数组中比第一个数组中大的值的下标)类似题目可以使用map存放第二个数组的下标和值的对应关系,key是值 value是索引位置。可以大大提高运行效率。用map.count判断是否存在第一个数组中的数字。
或者对一个数组先进行排序: 比如 1792. 【认证试题】服务器集群网络延迟 再找关键点进行计算。
3、栈:对于有效的括号等类似问题 可以使用 栈 来解决。
402. 移掉 K 位数字 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小,当前元素比栈顶小就移除栈顶 记录当前元素
单调栈:需要通过比较前后元素的大小关系来解决问题时我们通常使用单调栈。
316. 去除重复字母,使用map记录每个字符出现次数,使用单调增栈维护字典序从小到大,如果栈中不存在该元素就入栈,如果栈中的元素字典序比当前要入栈的大并且map中还存在栈中元素 就将当前元素出栈,后面还有机会进入。
3.1.单调栈里的元素具有单调性,栈中元素只能是单调递增或者单调递减
3.2.元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除;
3.3.使用单调栈可以找到元素向左遍历第一个比它小的元素,也可以找到元素向左遍历第一个比它大的元素。
单调栈这种数据结构,通常应用在一维数组上。如果遇到的问题,和前后元素之间的大小关系有关系的话,我们可以试图用单调栈来解决。在思考如何使用单调栈的时候,可以回忆一下这题的解题套路,然后想清楚,如果使用单调栈,每个元素出栈时候的意义。
stack<int> st;
//此处一般需要给数组最后添加结束标志符,具体下面例题会有详细讲解
运用单调栈必须有一个栈(存放索引下标) 和一个数组 (存放每个下标对应的结果)
for (遍历这个数组)
{
if (栈空 || 栈顶元素大于等于当前比较元素)
{
入栈;
}
else
{
while (栈不为空 && 栈顶元素小于当前元素)
{
栈顶元素出栈;
更新结果;
}
当前数据入栈;
}
}
4、BSF\DSF 类问题
5、递归类问题
6、并查集类问题
7、滑动窗口类问题
8、algorithm常用函数
8.1 充分利用sort和比较函数
static bool cmp(Medals& a, Medals& b)
count count_if
swap 交换两个数组\元素的值
reverse 转置
replace 将vector\string中所有的值替换成另一个值
返回数组中最大最小的数据
int a[] = {1,2,3,4,5}; int maxa = *max_element(a,a+5); int mina = *min_element(a,a+5);
9、链表的倒数第k个位置
// 让右指针先走k-1步
for (int i = 0; i < k - 1; i++) {
right = right->next;
}
//左右指针同时走,当右指针到达末尾,则左指针就在倒数第k个位置
while (right->next != nullptr) {
right = right->next;
left = left->next;
}
10.如果有多个元素就定义一个结构体进行表示,再定义一个结构体数组Input* input[50000];进行存储
结构体构造函数 Input(int i = 0, int j = 0, int k = 0) : a(i),b(j),c(k) {}
数组初始化:vector<int> finalResult(tasks.size(),-1);
11、每次做完一个题目后要思考下有没有其他解法,包括从别人的解答中学到其他解法,为啥自己没有想到,做一个题目吃透背后的套路,这才是根本。
12、两数求和问题
map、顺序数组使用左右指针移动、BSF二叉树先转换为数组 再排序后使用左右指针移动。
等差数列的求和公式:(a+b)*(b-a+1)/2 = sum(a,b) foxexp:18,19,20,21,22 = 100。
使用左右指针移动.
13.进制问题
// 十进制整数转为二进制中1的个数
int Solution::numerOf1(int n)
{
int count = 0;
while(n)
{
n = n & (n-1); // n&(n-1) 操作相当于把二进制表示中最右边的1变成0。
count++;
}
return count;
}
// 十进制整数转p进制字符串
string Solution::int2binay(int n, int p)
{
string res;
while(n) {
int t = n%p;
n = n/p;
res = to_string(t) + res;
}
return res;
}
14、单调栈
对于「循环数组」,常见的操作是将数组扩充一倍,即原数组为 [ 1 2 3 ] [1\ 2\ 3][1 2 3],扩充一倍后为 [ 1 2 3 1 2 3 ] [1\ 2\ 3 \ 1 \ 2\ 3][1 2 3 1 2 3]。扩充后的数组包含了循环数组中所有可能出现的序列,因此「扩充一倍」操作可以将循环数组转变为普通数组。
nums.resize(2*len); for (int i = len; i < 2*len; i++) nums[i] = nums[i-len];
用数组模拟栈,用一个变量来代表栈顶位置,从左至右遍历数组,若栈为空或当前数字小于等于栈顶数字,则将当前数字入栈。否则 当栈非空,并且当前数字大于栈顶数字,不断弹出栈顶元素,直至条件满足。
在弹出「栈顶元素」时,便可确定「栈顶元素」右边第一个比它大的数,即「当前元素」。若栈内元素始终未被弹出,则其右边没有数比它更大。
15、bitset 位图的使用
bitset<10> first; // empty bitset
bitset<10> second (120ul); // initialize from unsigned long
bitset<10> third (string("01011")); // initialize from string
cout << first << endl; // 00000 00000
cout << second << endl; // 00011 11000(120的二进制表示)
cout << third << endl; // 00000 01011
16、leetcode字符串类问题刷题总结