1. 输入多行字符串出错
1 2 3 4 5 6 7 8 9
| int n = 0; cin >> n; cin >> ws;
for (int i = 0; i < n; i++) { string line; getline(cin, line, '\n'); }
|
关键:使用**cin>>ws**
来吸收残存在输入流中的换行符
2. 判断字符串内容是否为整数
1 2 3 4 5 6 7 8
| bool isNumber(const string &str) { for (char const &c: str) { if (isdigit(c) == 0) { return false; } } return true; }
|
关键:调用**isdigit()**
函数,一个一个进行判断,不要嫌弃麻烦
3. 字符串按字符切割
1 2 3 4 5 6 7
| void stringSpilt(const string &str, const char split, vector<string> &res) { istringstream iss(str); string token; while (getline(iss, token, split)) { res.push_back(token); } }
|
关键:
- 调用
**istringstream iss (str)**
- 调用
**getline(iss,token,split)**
4. 修改哈希表中的值
方法一
1 2 3 4 5 6 7
| void setVariable(string &str, string &val) { checkVal(val); if (mapVal.count(str)){ mapVal.erase(str); } mapVal.insert({str, stoi(val)}); }
|
方法二
直接使用数组的表现形式进行增加或者修改
5. 字符串转数字
stoi
1 2 3 4 5
| cout << stoi("2") << endl; cout << stoi("21214 avb") << endl; cout << stoi("1000", nullptr, 2) << endl; cout << stof("221.4240") << endl; cout << stoi("221.4240") << endl;
|
6. 纯手工char数组转数字
写该函数时,涉及到的小的细节特别的多,需要条理清晰地进行解答。
index
问题,因为涉及到arr
和tmp
双数组,且分别用了i
j
count
三个数字来表示下标。因此,很容易出错。如果发现输入不同却输出相同时,很可能是下标**j**
** 使用时不小心打的是****count**
- 初始化问题。因为传入的cmd数组初始化时是
**char* cmd[20] = {'0'};**
。但是,最终赋值的时候,却初始化的是 **'\000'**
,对应的ASCII码值是0。而在这之中,我一直是以48的ASCII码值去进行计算。最终导致结果总是不对
- 下标和指数的不一致:该问题很经典。对于一个数组,读取时是需要从右往左读的,但是,这样子时,常用的
**i**
就不能直接作为pow的第二个参数使用,而是要额外使用一个变量。即:读取时是从右往左,计算时却是从左往右
- 最后的一个处理是char数组的结束符是跟随系统的变化而变化的,因此要十分小心。
- 关于负数🍀~蚌埠住了哇Σ(っ °Д °;)っ。还有小数的处理。要根据需要进行优化吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| int getNum(const char *cmd, int start) { char *tmp = (char *) malloc(sizeof(char) * DEF); for (int i = 0; i < DEF; ++i) { tmp[i] = '0'; } int count = 0; for (int j = start; j < DEF; ++j) { char x = cmd[j]; tmp[count] = cmd[j]; count++; } int ans = 0; int w = 0; for (int i = count - 1; i >= 0; --i) {
if (tmp[i] == 0) { continue; } ans += (tmp[i] - '0') * pow(10,w ); w++; } free(tmp); return ans; }
|
7. 去重
set+assign
在三数求和为0的题目中,需要进行去重。那么最好的方式是使用set
集合进行处理
1 2 3
| set<vector<int>> tmp{ans.begin(), ans.end()}; ans.assign(tmp.begin(), tmp.end()); return ans;
|
此处ans
中有重复的元素,则利用set<T>
进行 初始化后再重新赋值即可
- assign可以理解为利用迭代器重新进行赋值。那么其ans中的原本数据会丢失
函数原型是:
1:void assign(const_iterator first,const_iterator last);
2:void assign(size_type n,const T& x = T());
第一个相当于个拷贝函数,把first到last的值赋值给调用者;(注意区间的闭合-前闭后开)
第二个把n个x赋值给调用者;
sort+unique+erase
- unique函数属于STL中比较常用函数,它的功能是元素去重。即”删除”序列中所有相邻的重复元素(只保留一个)。此处的删除,并不是真的删除,而是指重复元素的位置被不重复的元素给占领了(详细情况,下面会讲)。由于它”删除”的是相邻的重复元素,所以在使用unique函数之前,一般都会将目标序列进行排序。
- unique函数通常和erase函数一起使用,来达到删除重复元素的目的。(注:此处的删除是真正的删除,即从容器中去除重复的元素,容器的长度也发生了变换;而单纯的使用unique函数的话,容器的长度并没有发生变化,只是元素的位置发生了变化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <algorithm> #include <vector>
using namespace std; int main() { int myints[] = {1,2,3,1,1}; int len = sizeof(myints)/sizeof(int); vector<int> vec(myints, myints + len); sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int x : vec) cout << x << ","; return 0; }
|
iterator unique(iterator it_1,iterator it_2);
这种类型的unique函数是我们最常用的形式。其中这两个参数表示对容器中[it_1,it_2)范围的元素进行去重(注:区间是前闭后开,即不包含it_2所指的元素),返回值是一个迭代器,它指向的是去重后容器中不重复序列的最后一个元素的下一个元素。
unique函数的去重过程实际上就是不停的把后面不重复的元素移到前面来,也可以说是用不重复的元素占领重复元素的位置。
8. 二分法
lower_bound
原型1:
1 2
| template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val);
|
原型2:
1 2
| template <class ForwardIterator, class T, class Compare> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);
|
模板参数解释
ForwardIterator
就是一个迭代器,vector< int > v
,v数组的首元素就是 v.begin()
T&val
, 就是一个T类型的变量
Compare
就是一个比较器,可以传仿函数对象,也可以传函数指针
函数作用:
前提是有序的情况下,lower_bound
返回指向第一个值不小于val
的位置,也就是返回第一个大于等于val
值的位置。(通过二分查找)
参数、返回值含义
- first,last: 迭代器在排序序列的起始位置和终止位置,使用的范围是
[first,last)
包括
first
到last
位置中的所有元素
- val: 在
[first,last)
下,也就是区分(找到大于等于val值的位置,返回其迭代器)
- comp: 主要针对于原型二,传一个函数对象,或者函数指针,按照它的方式来比较
- 返回值:返回一个迭代器,指向第一个大于等于val的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int main(){ vector<int> v= {3,4,1,2,8}; sort(v.begin(),v.end()); vector<int>::iterator iter1; vector<int>::iterator iter2; iter1 = lower_bound(v.begin(),v.end(),3); iter2 = lower_bound(v.begin(),v.end(),8); auto iter3 = lower_bound(v.begin(),v.end(),10); cout << *iter1 << endl; cout << *iter2 << endl; cout << *iter3 << endl; cout << iter1 - v.begin() << endl; cout << iter2 - v.begin() << endl; cout << iter3 - v.begin() << endl; cout << v.end() - v.begin() << endl; system("pause"); }
|
upper_bound
用法和上面类似。只是把lower_bound的大于等于换成大于。仿函数等等全是相同的用法
9. 迭代器
end()
容器的end()方法,返回一个迭代器,需要注意:这个迭代器不指向实际的元素,而是表示末端元素的下一个元素,这个迭代器起一个哨兵的作用,表示已经处理完所有的元素。
因此,在查找的时候,返回的迭代器,不等于end(),说明找到了目标。等于end(),说明检查了所有元素,没有找到目标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { for (int i = 0; i < matrix.size(); i++) { auto it = lower_bound(matrix[i].begin(),matrix[i].end(),target); if (it != matrix[i].end() && *it ==target) { return true; } } return false; } };
|
10. 自定类处理
vector存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class movie { public: int movieId; bool isRented; int price; int shopId;
movie(int movieId, int price, int shopId) { this->movieId = movieId; this->price = price; this->shopId = shopId; this->isRented = false; } };
|
对于movie
类,如果要用vector
存储,有以下可能的方式
1 2 3 4 5 6
| vector<movie> movieList;
vector<*movie> movieList;
vector<movie*> movieList;
|
建议不直接存储对象
STL
的存储实际上是拷贝,因此会重新调用构造函数,再进行赋值,开销大
- 从
STL
中获得的值也不是原来的对象,而是一份新的拷贝,所以存储的指针的值也会改变
- 因此,使用指针能够节省成本
STL删除
1 2 3 4 5 6 7
| list<obj *>m_list; list<obj *>::iterator ite; for( ite = m_list.begin(); ite != m_list.end(); ++ite) { delete (*ite); ite = m_list.erase(ite); }
|
先delete
,释放内存,在将其从容器中删除
错误
shop *shop = new class shop_(_shopId_)_;
auto *ptr = new class shop_(_shop_)_;
如果只使用shop *shop;
则在重新赋值的时候会出现错误
- 容器中最好存储指针,否则也会出现一些错误,使用指针在进行函数的调用和参数的传递时是比较方便的。
11. 自定义函数比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| vector<movie*> movieRented; std::sort(this->movieRented.begin(), this->movieRented.end(), compMovie); static bool compMovie(const movie *mov1, const movie *mov2) { if (mov1->price == mov2->price) { if (mov1->shopId == mov2->shopId) { return mov1->movieId < mov2->movieId; } return mov1->shopId < mov2->shopId; }
return mov1->price < mov2->price; } vector<vector<int>> target; std::sort(target.begin(), target.end(), compShop); static bool compShop(vector<int> x, vector<int> y) { if (x[1] == y[1]) { return x[0] < y[0]; } return x[1] < y[1];
}
|
12. 子串的寻找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <string> #include <cstring> using namespace std; int main() { string s1, s2; while(cin >> s1 >> s2) { if(s1.size() >= s2.size()) cout << (s1.find(s2) != string::npos) << endl; else cout << (s2.find(s1) != string::npos) << endl; } return 0; }
|
13. 得到子串
1 2 3 4
| str1.substr(index, num)
str1.substr(index)
|
14. 字符串大小写转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <string> using namespace std;
int main() { string s = "ABCDEFG";
for( int i = 0; i < s.size(); i++ ) { s[i] = tolower(s[i]); }
cout<<s<<endl; return 0; }
|
15. 字符串替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 1. string& replace(size_t pos, size_t n, const char *s);
从pos索引开始的n个字符,替换成字符串s
2. string& replace(size_t pos, size_t n, size_t n1, char c);
3. string& replace(iterator i1, iterator i2, const char* s);
void test7() { string s1("hello,world!");
cout<<s1.size()<<endl; s1.replace(s1.size()-1,1,1,'.');
s1.replace(6,5,"girl"); s1.replace(s1.begin(),s1.begin()+5,"boy"); cout<<s1<<endl; }
|
16. 字符串的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| string str:生成空字符串
string s(str):生成字符串为str的复制品
string s(str, strbegin,strlen):将字符串str中从下标strbegin开始、长度为strlen的部分作为字符串初值
string s(cstr, char_len):以C_string类型cstr的前char_len个字符串作为字符串s的初值
string s(num ,c):生成num个c字符的字符串
string s(str, stridx):将字符串str中从下标stridx开始到字符串结束的位置作为字符串初值
eg:
string str1; string str2("123456789"); string str3("12345", 0, 3); string str4("012345", 5); string str5(5, '1'); string str6(str2, 2);
1. size()和length():返回string对象的字符个数,他们执行效果相同。
2. max_size():返回string对象最多包含的字符数,超出会抛出length_error异常
3. capacity():重新分配内存之前,string对象能包含的最大字符数
|
17. 数字与字符串的相互转换
数字to字符串
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <sstream> using namespace std;
int main() { double x; string str; stringstream ss; cin >> x; ss << x; ss >> str; cout << str; return 0; }
|
方法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <iostream> #include <sstream> using namespace std;
int main() { double x; string str; cin >> x; str = to_string(x); cout << str; return 0; }
|
字符串to数字
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <string> using namespace std;
int main() { int x; string str; cin >> str; x = stoi(str); cout << x; return 0; }
|
方法二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <sstream> using namespace std;
int main() { double x; string str; stringstream ss; cin >> str; ss << str; ss >> x; cout << x; return 0; }
|
18. 溢出
1 2 3
| long long right = min(a,b)*(long long )n;
|
19. map遍历
1 2 3 4 5 6 7 8 9
| map<int,int>_map; map<int,int>::iterator iter; while(iter!=_map.end()){ cout << iter->first << ":" << iter->second<<endl; iter++; } for(iter = _map.begin(); iter != _map.end(); iter++) { cout << iter->first << " : " << iter->second << endl; }
|