C++: string讲解 前序
目录
STL简介:
stl容器的头文件和std标准库的关系:
string的介绍:
<1>string类和char*转换:—————补充————————
(1)string转char*
(2)char*转string
<2>char*转int
(1)atoi:
(2)stoi
(3)strtol
<3>int转char*
———————————————————————————————
string类对象大小
string类对象的输入——getline(cin, a); 新增!
一.string类对象的常见构造函数
(2)单参数的构造函数支持隐式类型转换
二.string类对象的常见析构函数
三.string类对象的赋值 std::string::operator=
四.std::string::operator[]
1.有两个函数重载:
2.使用
【1】题目1:遍历对象的每一个字符,三种做法:
(1)用 std::string::operator[](解决“遍历对象的每一个字符”①)
(2)迭代器(解决“遍历对象的每一个字符”②)
(3)范围for—语法糖(解决“遍历对象的每一个字符”③)
【2】相关练习题目:917. 仅仅反转字母
(1)做法一:利用下标+[] (已知物理空间是连续的,如果是链表就只能用迭代器)
(2)迭代器做法
3.std::string::operator[] 和 std::string::at
五.迭代器(共四种迭代器)
1.正向迭代器
(1)正向迭代器
2.反向迭代器
(1)反向迭代器
3.const正向迭代器 和 4. const反向迭代器
六.string类中的其他用法
string类可以用==判断相等
1.几个小用法
2.std::string::reserve
3.std::string::resize
(1)例一
(2)例二
4.push_back; append operator+=
5.插入数据: insert()
题目:415. 字符串相加
6.删除数据: erase()
7.交换对象:swap()
8.返回C格式字符串 c_str
9.std::string::find 和 rfind
(1)find
(2)rfind 从后往前取
10. std::string::substr
11.std::getline (string)
题目:HJ1 字符串最后一个单词的长度
12.std::string::find_first_of
题目:387. 字符串中的第一个唯一字符
STL简介:
stl容器的头文件和std标准库的关系:
头文件:#include<string> (不加.h,C语言中有string.h,防止和C语言的重复)<iostream>头文件除输入输入函数以外也包含<utility>和stl的所有容器的定义和部分容器的声明。部分容器的声明解释:有的容器在std标准库中有声明,有的stl容器在std标准库中没声明。例如string在std标准库中有声明,unordered_map在std标准库中无声明,即:<iostream>头文件包含了string的声明,但不包含unordered_map的声明,所以不加#include<string>,不加using namespace std;不放开标准库,直接用#include<iostream> ,只需要加上std这个域:std::string就可以正常使用,因为<iostream>头文件有string的声明;但是对于unordered_map,因为<iostream>不包含unordered_map的声明,所以你必须加上#include<unordered_map>里面有声明,才能正常使用unordered_map:
在加上<iostream>前提下,如果加#include<unordered_map>声明,但不加using namespace std; 不把标准库打开,就需要std::限定才能用否则不能用;如果加using namespace std; 打开了标准库,则std::加不加都可以。
若不加#include<unordered_map>,则没有声明,即使加上 std::限定 也用不了。
string的介绍:
typedef basic_string<char> string; (string是一个类模板)
1.解释:Strings are objects that represent sequences of characters. (strings 是管理字符串的一个类)
2.作用:管理动态增长字符数组,这个字符串以\0结尾
3.底层:类似于下面这样:底层是new一个新空间,再拷贝常量字符串进去,为什么不能直接
_str=str ? 这样做不行,他们指向同一块空间,都是指向常量字符串了,常量字符串无法实现增删查改
namespace bit
{template<class T>class basic_string{public:basic_string(const T* str){// 开空间存储字符串,方便增删查改size_t len = strlen(str);_str = new T[len + 1];strcpy(_str, str);}private:const T* _str;size_t _size;size_t _capacity;};
}typedef basic_string<char> string;int main(){string s("hello world");}
<1>string类和char*转换:—————补充————————
(1)string转char*
std::string str = "string";
const char *cstr = str.c_str();
(2)char*转string
可以直接赋值。
char *cstr = “hello”;
string sss;
sss = cstr;
<2>char*转int
(1)atoi:
(2)stoi
#include <cstdlib>
int main()
{//int a=atoi("123");int a=stoi("123");printf("%d\n",a);return 0;
}
(3)strtol
<3>int转char*
(1)to_string
———————————————————————————————
string类对象大小
string类对象的输入——getline(cin, a); 新增!
cin和cout写输入输出非常方便,但是用cin输入string字符串时,默认遇到空格回车制表符等空白字符即字符串输入结束。
#include <iostream>
#include <string>
using namespace std;int main() {string a, b;cin >> a >> b;cout << "a:" << a << endl;cout << "b:" << b << endl;return 0;
}/*
输入:
abc 123
输出:
a:abc
b:123
*/
但是遇到带空格字符的字符串就不是很友好了,则需要用到getline函数,getline()是遇回车符输入结束。
#include <iostream>
#include <string>
using namespace std;int main() {string a, b;getline(cin, a);getline(cin, b);cout << "a:" << a << endl;cout << "b:" << b << endl;return 0;
}/*
输入:
abc 123
123 abc
输出:
a:abc 123
b:123 abc
*/
一.string类对象的常见构造函数
(1)
1.string(); 是无参的构造函数。
2.string (const char* s); 是有参构造函数。
3.string (const string& str); 是拷贝构造函数。
4.string (const char* s, size_t n); 是用字符串s的前n个字符初始化
5.string(size_t n, char c);初始化成n个字符c
6.string (const string& str, size_t pos,size_ t len = npos);用string类型对象str的第pos个位置后的len个字符初始化(pos是position位置的缩写,缺省参数npos是 static const size_t npos = -1; 也就是正数里面的最大值,是4294967295:如果pos后面不够取,str太短了,那就取完为止,npos意思是把pos位置后面的取完)
#include<iostream>
#include<string>
using namespace std;
int main()
{string s1; // 1.string(); 相当于string s1(""); string s2("hello world"); // 2.string (const char* s); string s3(s2); // 3.string (const string& str); string s4 = s2; // 3.string (const string& str); string s5("aaabbbcccddd",3);// 4.string (const char* s, size_t n);string s6(10, 'x'); // 5.string(size_t n, char c);
// 6.string (const string& str, size_t pos,size_ t len = npos);string s7(s2, 6, 3); string s8(s2, 6, 100);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;cout << s7 << endl;cout << s8 << endl;
}
(2)单参数的构造函数支持隐式类型转换
string s="hello"; 这句,字符串"hello"会先进行隐式类型转换,直接构造一个string类型的"hello",然后这个string类的"hello"拷贝构造给s,但会被编译器优化成直接构造,先构造再拷贝构造——>通过编译器优化就成了直接构造
string s("hello");
string s="hello";
详情见:此文章的大标题三——>小标题2
(88条消息) C++:1.流插入与流提取的运算符重载,2.初始化列表,3.explicit关键字,4.静态成员变量与非静态成员变量用法 详解_beyond.myself的博客-CSDN博客_流插入流提取
二.string类对象的常见析构函数
用途是清理动态资源,不用管,自动调用
三.string类对象的赋值 std::string::operator=
string& operator= (const string& str); 把string类对象赋值成另一个string类对象str(这个是最常用的)
string& operator= (const char* s); 把string类对象赋值成字符串s
string& operator= (char c); 把string类对象赋值成字符c
void test_string2()
{string s1("hello");string s2("xxx");s1 = s2; //string& operator= (const string& str);s1 = "yyy"; //string& operator= (const char* s);s1 = "y"; //string& operator= (char c);
}
int main()
{test_string2();return 0;
}
四.std::string::operator[]
s1[i] 就相当于 s1.operator[](i); string类对象s1的第i个字符
1.有两个函数重载:
char& operator[](size_t pos) 可读可写
const char& operator[](size_t pos) const 只读
底层逻辑:
namespace bit
{class string{public:// 值修改返回对象char& operator[](size_t pos){assert(pos <= _size); //检查是否越界return _str[pos];}const char& operator[](size_t pos) const{assert(pos <= _size);return _str[pos];}private:char* _str;size_t _size;size_t _capacity;};
}
void test_string4()
{ string s1("hello"); //调用可读可写const string s2("hello"); //调用只读}
int main()
{test_string4();return 0;
}
2.使用
以前的内置类型[]:
const char* s2 = "world";s2[i]; // *(s2+i)
string中的自定义类型用 std::string::operator[]:
【1】题目1:遍历对象的每一个字符,三种做法:
第一种方式,下标+[]
第二种方式,迭代器
第二种方式,范围for
( s1.size()是计算对象中的字符个数,不包含\0)
(1)用 std::string::operator[](解决“遍历对象的每一个字符”①)
void test_string3()
{// 遍历string的每一个字符string s1("hello");cout << s1.size() << endl;// 第一种方式,下标+[]for (size_t i = 0; i < s1.size(); i++){// s1.operator[](i);cout << s1[i] << " ";}cout << endl;
}
int main()
{test_string3();return 0;
}
(2)迭代器(解决“遍历对象的每一个字符”②)
例1:遍历对象的每一个字符:第二种方式,迭代器
介绍:迭代器是什么? -像指针一样的东西或者就是指针(像指针一样的访问数据结构的东西)
各个类都有独自的迭代器 iterator ,所以要指定是哪个类的,string类中的迭代器写作
string: : iterator
s1.begin()返回第一个位置的指针(或者说第一个位置的迭代器)
s1.end()返回最后一个数据的下一个位置,下面这里的 s1.end() 就是\0的位置
void test_string3()
{// 遍历string的每一个字符string s1("hello");cout << s1.size() << endl;// 迭代器string::iterator it = s1.begin(); //it是s1的首元素地址while (it != s1.end()) //遍历打印,直到it为 \0 停止{ cout << *it << " ";++it;}cout << endl;
}
int main()
{test_string3();return 0;
}
小疑问:这里 while (it != s1.end()) 可以写成 while (it < s1.end())吗?
答:这里是可以,因为是顺序表,存储空间连续,如果像后面的链表形式存储空间不连续就只能用标准的 while (it != s1.end()) 。
例2:vector顺序表
#include<iostream>
#include<vector>
#include<string>
using namespace std;void test_string3()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator vit = v.begin();while (vit != v.end()){cout << *vit << " ";++vit;}cout << endl;
}
int main()
{test_string3();return 0;
}
(3)范围for—语法糖(解决“遍历对象的每一个字符”③)
范围for -- 底层:编译器替换成了迭代器 (这里简答了解一下)
void test_string3()
{// 遍历string的每一个字符string s1("hello");cout << s1.size() << endl;// 范围for -- 原理:替换成迭代器for (auto ch : s1) //自动取s1中的数据赋值给ch,自动判断结束{cout << ch << " ";}cout << endl;
}
int main()
{test_string3();return 0;
}
【2】相关练习题目:917. 仅仅反转字母
给你一个字符串 s ,根据下述规则反转字符串:
所有非英文字母保留在原有位置。
所有英文字母(小写或大写)位置反转。
返回反转后的 s 。
示例 1:
输入:s = "ab-cd"
输出:"dc-ba"
示例 2:
输入:s = "a-bC-dEf-ghIj"
输出:"j-Ih-gfE-dCba"
示例 3:
输入:s = "Test1ng-Leet=code-Q!"
输出:"Qedo1ct-eeLg=ntse-T!"
(1)做法一:利用下标+[] (已知物理空间是连续的,如果是链表就只能用迭代器)
class Solution {
public:bool isletter(char ch){if(ch>='a'&&ch<='z')return true;else if(ch>='A'&&ch<='Z')return true;elsereturn false;}string reverseOnlyLetters(string s) {int left=0,right=s.size()-1;while(left<right){while(left<right && !isletter(s[left])) left++;while(left<right && !isletter(s[right]))right--;swap(s[left],s[right]);left++;right--;} return s; }
};
(2)迭代器做法
class Solution {
public:bool isletter(char ch){if(ch>='a'&&ch<='z')return true;else if(ch>='A'&&ch<='Z')return true;elsereturn false;}string reverseOnlyLetters(string s) {string::iterator leftIt=s.begin();string::iterator rightIt=s.end()-1; //end()是\0, s.end()-1 是最后一个字符while(leftIt<rightIt){while(leftIt<rightIt && !isletter(*leftIt)) leftIt++;while(leftIt<rightIt && !isletter(*rightIt))rightIt--;swap(*leftIt,*rightIt);leftIt++;rightIt--;} return s; }
};
3.std::string::operator[] 和 std::string::at
用法一样,处理方式不一样,越界时 operator[]通过断言抛异常,at抛越界异常
void test_string4()
{string s1("hello");const string s2("hello");s1[0];s1.at(0);s1[0] = 'x';//s2[0] = 'x';s1.at(0) = 'y';
}
int main()
{test_string4();return 0;
}
五.迭代器(共四种迭代器)
介绍:迭代器是什么? -像指针一样的东西或者就是指针
各个类都有独自的迭代器 iterator ,所以要指定是哪个类的,string类中的迭代器写作
string: : iterator
s1.begin()返回第一个位置的指针(或者说第一个位置的迭代器)
s1.end()返回最后一个数据的下一个位置
1.正向迭代器
(1)正向迭代器
还是以 题目1:遍历对象的每一个字 为例
void test_string5()
{// 遍历string的每一个字符string s1("hello");cout << s1.size() << endl;// 迭代器string::iterator it = s1.begin(); //it是s1的首元素地址while (it != s1.end()) //遍历打印,直到it为 \0 停止{ cout << *it << " ";++it;}cout << endl;
}
int main()
{test_string5();return 0;
}
2.反向迭代器
(1)反向迭代器
void test_string5()
{// 正向迭代器string s("hello world");string::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;// 反向迭代器string::reverse_iterator rit = s.rbegin(); // s.rbegin() 表示最后一个字母d的指针while (rit != s.rend()) // s.rend() 表示首字母h的指针{cout << *rit << " ";++rit; //反向迭代器也是++}cout << endl;
}int main()
{test_string5();return 0;
}
3.const正向迭代器 和 4. const反向迭代器
常规的正向迭代器和反向迭代器是可以修改string类对象的内容的:
void test_string5()
{// 正向迭代器string s("hello world");string::iterator it = s.begin();while (it != s.end()){(*it) += 1; //修改string类对象的内容cout << *it << " ";++it;}cout << endl;cout << s << endl;// 反向迭代器string::reverse_iterator rit = s.rbegin();while (rit != s.rend()){(*rit) -= 1; //把string类对象的内容改回去cout << *rit << " ";++rit;}cout << endl;cout << s << endl;
}int main()
{test_string5();return 0;
}
const正向迭代器和const反向迭代器:
const正向迭代器:
此处调用只读类型的 const_iterator begin() const;
只读类型的 const_iterator end() const;
const反向迭代器:
调用只读类型的 const_reverse_iterator begin() const;
只读类型的 const_reverse_iterator rend() const;
void Func(const string& rs) //传参时转为const类型
{string::const_iterator it = rs.begin(); while (it != rs.end()){//*it += 1; × 不可以修改cout << *it << " ";++it;}cout << endl;//string::const_reverse_iterator rit = rs.rbegin(); 前面类型太长可以考虑用autoauto rit = rs.rbegin();while (rit != rs.rend()){//(*rit) -= 1; × 不可以修改cout << *rit << " ";++rit;}cout << endl;
}void test_string6()
{// 正向迭代器string s("hello world");Func(s);
}
六.string类中的其他用法
string类可以用==判断相等
#include<iostream>
using namespace std;
#include<string>
int main()
{string s1("hello");string s2("hello");if (s1 == s2){cout << "相等";}return 0;
}
1.几个小用法
length() 和 size() 一样,都是显示对象中字符串长度,size常用(length是早起写法,不常用)
max_ size() 显示字符串最大能开多长,没什么用
capacity() 显示对象的总容量
2.std::string::reserve
reserve:提前开好n字节空间,不一定是正好n个字节,为了对齐还要多开几个
利用s.push_back( ); 向对象中添加字符,每次容量满了就会扩容1.5倍,很麻烦,已知要添加1000个字符,所以用 reserve:提前开好1000字节空间
void test_string6()
{string s;size_t sz = s.capacity();cout << "making s grow:\n";cout << "capacity changed: " << sz << '\n';for (int i = 0; i < 1000; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}}
int main()
{test_string6();return 0;
}
用 reserve:提前开好1000字节空间
void test_string6()
{string s;size_t sz1 = s.capacity();cout << "capacity changed: " << sz1 << '\n'; //查看初始容量s.reserve(1000); //提前开好1000字节空间size_t sz = s.capacity();cout << "making s grow:\n";cout << "capacity changed: " << sz << '\n'; //查看reserve后的容量for (int i = 0; i < 1000; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}}
int main()
{test_string6();return 0;
}
3.std::string::resize
resize是开空间并初始化
(1)例一
void test_string6()
{string s1;string s2;//s.reserve(1000); // 扩空间s1.resize(1000); // 扩空间+初始化s2.resize(1000, 'x'); // 扩空间+初始化}
int main()
{test_string6();return 0;
}
(2)例二
VS下:reverse不能缩小容量;resize也不能缩小容量,但能去掉前10个后面所有的内容
void test_string6()
{string s1;string s2;s1.resize(100, 'c');s2.resize(100, 'x');s1.reserve(10);s2.resize(10);}
int main()
{test_string6();return 0;
}
4.push_back; append operator+=
插入一个字符用push_back;插入字符串用append;最好用的还是+=
void test_string6()
{string s;s.push_back('x');s.append("hello");string str("world");s.append(str);cout << s << endl;s += 'x';s += "hello";s += str;cout << s << endl;
}
int main()
{test_string6();return 0;
}
+=:
void test_string8()
{string s("hello");s += " ";s += "world";cout << s << endl;
}
int main()
{test_string8();return 0;
}
5.插入数据: insert()
void test_string8()
{string s("hello");s.insert(0, 1, 'a'); //在第0个位置插入一个字符as.insert(s.begin(), 'b'); //在第0个位置插入一个字符acout << s << endl;s.insert(3, 1, 'x');s.insert(s.begin()+3, 'y'); //里面放迭代器cout << s << endl;
}
int main()
{test_string8();return 0;
}
insert 如果头插的话,第二次头插数据把后面1个挪动1次,第三次头插数据把后面2个挪动1次,……,第n次头插数据把后面n-1个挪动1次,等差数列相加后时间复杂度是O(N²),不如使用+=后逆置reverse( retStr.begin(), retStr.end()); 可以使时间复杂度降低到O(N) :
题目:415. 字符串相加
class Solution {
public:string addStrings(string num1, string num2) {int end1=num1.size()-1;int end2=num2.size()-1;int carry=0;string retStr;while(end1>=0||end2>=0){int val1= end1>=0?num1[end1]-'0':0;int val2= end2>=0?num2[end2]-'0':0;int ret=val1+val2+carry;if(ret>9){carry=1;ret-=10;}elsecarry=0;retStr+=ret+'0'; //这里如果用retStr.insert(retStr.begin(),ret+'0')效率低end1--;end2--;}if(carry==1){retStr+='1';}reverse( retStr.begin(), retStr.end());return retStr;}
};
6.删除数据: erase()
void test_string8()
{string s("hello world");cout << s << endl;s.erase(s.begin()); //删除迭代器所在位置的字符,删除首字符cout << s << endl;s.erase(s.begin() + 3); //删除第3个字符cout << s << endl;s.erase(3, 2); //删除包括第3个字符开始后面的2个字符cout << s << endl;//s.erase(3); //删除包括第3个字符开始后面所有值,因为缺省值npos是最大正数s.erase(3, 100); //超出就有多少删多少cout << s << endl;
}
int main()
{test_string8();return 0;
}
当用第三种时,删除区间是左闭右开
void test_string14()
{string s("hello world");cout << s << endl;s.erase(s.begin(),s.begin()+2); cout << s << endl;}
int main()
{test_string14();return 0;
}
7.交换对象:swap()
void test_string9()
{string s1("hello world");string s2("string");// C++98s1.swap(s2); // 效率高:直接交换指针swap(s1, s2); // 效率低:库中的交换函数,是深拷贝交换
}
int main()
{test_string9();return 0;
}
STL中的swap函数底层是深拷贝交换:
8.返回C格式字符串 c_str
const char* c_str() const;
获取C字符串等效
返回指向数组的指针,该数组包含以空结尾的字符序列(即C字符串),表示字符串对象的当前值。
此数组包含构成字符串对象值的相同字符序列,最后添加一个终止空字符(“\0”)。
string s1("hello world");cout << s1 << endl;cout << s1.c_str() << endl;
注意:他返回的是指针,例如下面的对象a和b就算值一样,但他们的返回值是指针,即a.c_str()==b.c_str()比较的是存储字符串位置的地址,不相同,a.c_str() == b.c_str()为假。
int main(int argc, char* argv[])
{string a = "hello world";string b = a;if (a.c_str() == b.c_str()){cout << "true" << endl;}else cout << "false" << endl;return 0;
}
9.std::string::find 和 rfind
(1)find
返回找的第一个字符的起始位置,找不到就返回npos(npos=42亿9千万...)
file.find('.'); 对应第四种用法:size_t find (char c, size_t pos = 0) const; ,'.'对应char c,size_t pos = 0 缺省值是0说明默认从0开始找字符c
void test_string10()
{// 要求取出文件的后缀string file("string.cpp");size_t pos = file.find('.'); //size_t find (char c, size_t pos = 0) const;if (pos != string::npos){//string suffix = file.substr(pos, file.size() - pos); string suffix = file.substr(pos); //和下面一样,都是取完后面所有的字符cout << file << "后缀:" << suffix << endl;}else{cout << "没有后缀" << endl;}
}
int main()
{test_string10();return 0;
}
(2)rfind 从后往前取
void test_string10()
{string file("string.c.tar.zip");size_t pos = file.rfind('.');if (pos != string::npos){string suffix = file.substr(pos);//string suffix = file.substr(pos,file.size()-pos);cout << file << "后缀:" << suffix << endl;}else{cout << "没有后缀" << endl;}
}
int main()
{test_string10();return 0;
}
10. std::string::substr
string substr (size_t pos = 0, size_t len = npos) const;
从pos位置往后取(包括pos位置字符)len个字符,返回取出的这一串string类型的字符。默认缺省参数npos是最大正值。
int main()
{std::string str("Please, replace the vowels in this sentence by asterisks.");std::cout << str.substr(6,8) << '\n';return 0;
}
void test_string11()
{// 取出url中的域名string url1("http://www.cplusplus.com/reference/string/string/find/");string url2("https://leetcode.cn/problems/design-skiplist/solution/tiao-biao-probabilistic-alternative-to-b-0cd8/");string& url = url1;// 协议 域名 uristring protocol;size_t pos1 = url.find("://");if (pos1 != string::npos){protocol = url.substr(0, pos1);cout << "protocol:" << protocol << endl;}else{cout << "非法url" << endl;}string domain;size_t pos2 = url.find('/', pos1 + 3);if (pos2 != string::npos){domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));cout << "domain:" << domain << endl;}else{cout << "非法url" << endl;}string uri = url.substr(pos2 + 1);cout << "uri:" << uri << endl;
}
int main()
{test_string11();return 0;
}
11.std::getline (string)
用法是:cin遇到空格或换行就会停下,getline只认换行,遇到空格不会停
题目:HJ1 字符串最后一个单词的长度
#include <iostream>
#include <string>
using namespace std;int main(){string str;getline(cin,str); //getline用法size_t pos = str.rfind(' ');cout << str.size()-pos-1;return 0;
}
12.std::string::find_first_of
在string类对象中找到第一个出现的字符c,返回此字符的下标值。
int main()
{std::string str("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_of("e");int a = 4;while (a--){str[found] = '*';found = str.find_first_of("e", found + 1);}std::cout << str << '\n';return 0;
}
如果找字符串的话,找到包含字符中出现的第一个,并返回下标值
int main()
{std::string str("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_of("aeiou");int a = 4;while (a--){str[found] = '*';found = str.find_first_of("aeiou", found + 1);}std::cout << str << '\n';return 0;
}
题目:387. 字符串中的第一个唯一字符
class Solution {
public:int firstUniqChar(string s) {int count[26]={0};for(char ch:s){count[ch-'a']++;}for(int i=0;i<s.size();i++){if(count[s[i]-'a']==1)return i;}return -1;}
};
C++: string讲解 前序相关推荐
- 简单讲解前序遍历,中序遍历,后序遍历和层次遍历
如果你按照 根节点 -> 左孩子 -> 右孩子 的方式遍历,即「先序遍历」,每次先遍历根节点,遍历结果为:1 2 4 5 3 6 7: 同理,如果你按照 左孩子 ...
- java根据前序和中序建树_(Java实现)二叉树---根据前序、中序、后序数组还原二叉树...
概述在上一篇文章中讲到顺序存储二叉树,一般是用于完全二叉树,通过统一的数学公式可以将数组还原成完全二叉树 而对于普通的二叉树来说,也可以根据前序.中序和后序遍历得到的数组,还原二叉树 还原还原的情况分 ...
- String、StringBuffer和StringBuilder的详解
目录 一.String讲解 1.String(String字符串常量) 2.String 拼接方式与性能的影响 二.StringBuffer 和 StringBuilder 讲解 1.StringBu ...
- 二叉树 ---- 前序 中序 后序 知二求一
二叉树 ---- 前序 中序 后序 知二求一 先说一下什么是二叉树的前中后序; 根:根节点 左代表遍历左子树 右代表遍历右子树 前序:根-左---右 中序:左-根---右 后序:左-右---根 如图求 ...
- Java数据结构与算法:二叉树
原文链接:http://www.cnblogs.com/skywang12345/p/3576452.html 1. 二叉查找树简介 二叉查找树(Binary Search Tree),又被称为二叉搜 ...
- 二叉查找树(二)之 C++的实现
二叉查找树(二)之 C++的实现 概要 上一章介绍了"二叉查找树的相关理论知识,并通过C语言实现了二叉查找树".这一章给出二叉查找树的C++版本.这里不再对树的相关概念进行介绍,若 ...
- 二叉查找树(一)之 C语言的实现
二叉查找树(一)之 图文解析 和 C语言的实现 概要 本章先对二叉树的相关理论知识进行介绍,然后给出C语言的详细实现.关于二叉树的学习,需要说明的是:它并不难,不仅不难,而且它非常简单.初次接触树的时 ...
- 【编程3】二叉树遍历(LeetCode.102)
文章目录 一.二叉树的层次遍历 1.题目描述--LeetCode.102 2.分析 3.实现 二.二叉树(Binary Tree) 1.相关概念 二叉树 满二叉树 完全二叉树 区分 2.二叉树的表示( ...
- DP专练1( [NOIP 2003]加分二叉树 + 太空梯 )
我们先慢慢来 加分二叉树 题目 题解 简单讲解前序//中序//后序遍历 代码实现 太空梯 题目 题解 代码实现 加分二叉树 题目 题解 简单讲解前序//中序//后序遍历 其实说白了,这个*序就是根ro ...
最新文章
- 024_Word知识汇总
- mysql中usage是什么权限?
- 【vue】webpack打包vue项目并且运行在Tomcat里面
- 灯的开关 Bulb Switcher II
- 2017年第八届蓝桥杯C/C++ C组国赛 —— 第四题:小数第n位
- silverlight: [HtmlPage_NotEnabled] 调试资料字符串不可用的解决
- C#的特性Attribute
- ubuntu下,rubyonrails环境搭建
- 做H5页面用什么软件比较好?
- SQLMAP注入拖库过程 1
- 自用frp服务器分享及客户端配置连接教程
- mysql deadlock found_MySQL遇到Deadlock found when trying to get lock,解决方案
- LaTeX引文.bib方式插入——misplaced alignment tab character . ...ock{\em IEEE Transactions onSystems Man
- android 自定义心电图,Android动态滚动波形图(心电图)的实现
- 什么是集成测试?集成测试方法有哪些?
- 计算机无法信任的英文,关于信任的英语名言佳句语录
- 管人就是管情绪——从《纸牌屋》中的心理操控说起
- 要玩就玩最好的棋牌游戏
- MQTT+ActiveMQ实现消息推送(移动端)
- 华为HiLink智慧家庭生态发布 引领未来智能生活
热门文章
- Java Socket udp协议在网络读卡器上的使用
- Linux 中 exit 的意思
- java 用数组存储书籍信息_有大神会编下这样的简单系统嘛,Java的,用数组存储信息!...
- cf进不去服务器 正在连接,Win7电脑CF连接服务器失败如何解决 CF连接不到服务器怎么办...
- 高德地图轨迹展示样式修改
- 关键周!非农携众多重量级数据来袭、黄金多头冲击千八大关!
- BIOS SETUP UTILITY
- 一瓶汽水1块钱,3个瓶盖换一瓶汽水,2个空瓶换一瓶汽水,假如手里有5块钱,能喝多少瓶汽水
- 红魔馆爆炸了---湖南科技大学oj1975---尺取法
- 有关Maven依赖中的version