diff --git a/C++/标准库/5 字符串.md b/C++/标准库/5 字符串.md index e4e2225d..838386bc 100644 --- a/C++/标准库/5 字符串.md +++ b/C++/标准库/5 字符串.md @@ -1,11 +1,34 @@ -## 1 string容器的操作 +## 1 string字符串容器和泛型算法 + +### 1.1 STL顺序容器 > 参考顺序容器部分 +### 1.2 STL泛型算法 +* string 对象也可以看作一个顺序容器,它支持随机访问迭代器,也有 begin 和 end 等成员函数。STL 中的许多算法也适用于 string 对象。下面是用 STL 算法操作 string 对象的程序示例。 + +```C++ +#include +#include +#include +using namespace std; +int main() +{ + string s("afgcbed"); + string::iterator p = find(s.begin(), s.end(), 'c'); + if (p!= s.end()) + cout << p - s.begin() << endl; //输出 3 + sort(s.begin(), s.end()); + cout << s << endl; //输出 abcdefg + next_permutation(s.begin(), s.end()); + cout << s << endl; //输出 abcdegf + return 0; +} +``` ## 2 string字符串操作 -## 2.1 构造函数 +## 2.1 字符串创建 * string 类有多个构造函数,用法示例如下: ```C++ string s1(); // si = "" @@ -35,21 +58,18 @@ s2.assign(s1, 1, 2); // s2 = "23",即 s1 的子串(1, 2) s2.assign(4, 'K'); // s2 = "KKKK" s2.assign("abcde", 2, 3); // s2 = "cde",即 "abcde" 的子串(2, 3) ``` -## 2.3 字符串长度 +## 2.3 字符串交换 + +* swap 成员函数可以交换两个 string 对象的内容。例如: +```C++ +string s1("West”), s2("East"); +s1.swap(s2); // s1 = "East",s2 = "West" +``` + +## 2.4 字符串长度 * int length() 成员函数返回字符串的长度。 * int size() 成员函数可以实现同样的功能。 -## 2.4 字符串拼接 -* +和+=运算符对string 对象执行字符串的连接操作 -* append 成员函数,可以用来向字符串后面添加内容。append 成员函数返回对象自身的引用。 - -```C++ -string s1("123"), s2("abc"); -s1.append(s2); // s1 = "123abc" -s1.append(s2, 1, 2); // s1 = "123abcbc" -s1.append(3, 'K'); // s1 = "123abcbcKKK" -s1.append("ABCDE", 2, 3); // s1 = "123abcbcKKKCDE",添加 "ABCDE" 的子串(2, 3) -``` ## 2.5 字符串比较 * 可以用 <、<=、==、!=、>=、> 运算符比较 string 对象 * compare 成员函数可用于比较字符串。compare 成员函数有以下返回值: @@ -66,39 +86,26 @@ n = s1.compare("Hello"); n = s1.compare(1, 2, "Hello"); //比较 s1 的子串(1,2)和"Hello” n = s1.compare(1, 2, "Hello", 1, 2); //比较 s1 的子串(1,2)和 "Hello" 的子串(1,2) ``` -## 2.6 字符串子串 -* substr 成员函数可以用于求子串 (n, m),原型如下: -```C++ -string substr(int n = 0, int m = string::npos) const; -``` -* 调用时,如果省略 m 或 m 超过了字符串的长度,则求出来的子串就是从下标 n 开始一直到字符串结束的部分。例如: -```C++ -string s1 = "this is ok"; -string s2 = s1.substr(2, 4); // s2 = "is i" -s2 = s1.substr(2); // s2 = "is is ok" -``` -## 2.7 字符串交换 -* swap 成员函数可以交换两个 string 对象的内容。例如: -```C++ -string s1("West”), s2("East"); -s1.swap(s2); // s1 = "East",s2 = "West" -``` - -## 2.8 查找字符串(字符) +## 2.6 查找字符串(字符) * string 类有一些查找子串和字符的成员函数,它们的返回值都是子串或字符在 string 对象字符串中的位置(即下标)。 * 如果查不到,则返回 **string::npos**。string: :npos 是在 string 类中定义的一个静态常量。这些函数如下: -* `find`:从前往后查找子串或字符出现的位置。 -* `rfind`:从后往前查找子串或字符出现的位置。 -* `find_first_of`:从前往后查找何处出现另一个字符串中包含的字符。 -* `find_last_of`:从后往前查找何处出现另一个字符串中包含的字符。 -* `find_first_not_of`:从前往后查找何处出现另一个字符串中没有包含的字符。 -* `find_last_not_of`:从后往前查找何处出现另一个字符串中没有包含的字符。 + * `find`:从前往后查找子串或字符出现的位置。 + * `rfind`:从后往前查找子串或字符出现的位置。 + * `find_first_of`:从前往后查找何处出现另一个字符串中包含的字符。 + * `find_last_of`:从后往前查找何处出现另一个字符串中包含的字符。 + * `find_first_not_of`:从前往后查找何处出现另一个字符串中没有包含的字符。 + * `find_last_not_of`:从后往前查找何处出现另一个字符串中没有包含的字符。 +* 所有的字符串查找方法重载了以下四种类型:pos表示开始查找的位置。n表示查找匹配的次数。返回值是整数索引。 + * string (1) size_t find (const string& str, size_t pos = 0) const noexcept; + * c-string (2) size_t find (const char* s, size_t pos = 0) const; + * buffer (3) size_t find (const char* s, size_t pos, size_type n) const; + * character (4) size_t find (char c, size_t pos = 0) const noexcept; ```C++ #include #include @@ -131,8 +138,46 @@ int main() return 0; } ``` + +## 2.7 字符串拼接 +* +和+=运算符对string 对象执行字符串的连接操作 +* append 成员函数,可以用来向字符串后面添加内容。append 成员函数返回对象自身的引用。 + * string& append (const string& str); + * string& append (const string& str, size_t subpos, size_t sublen); + * string& append (const char* s); + * string& append (const char* s, size_t n); + * string& append (size_t n, char c); + * string& append (InputIterator first, InputIterator last); +```C++ +string s1("123"), s2("abc"); +s1.append(s2); // s1 = "123abc" +s1.append(s2, 1, 2); // s1 = "123abcbc" +s1.append(3, 'K'); // s1 = "123abcbcKKK" +s1.append("ABCDE", 2, 3); // s1 = "123abcbcKKKCDE",添加 "ABCDE" 的子串(2, 3) +``` +## 2.8 字符串剪切 +* substr 成员函数可以用于求子串 (n, m),原型如下。调用时,如果省略 m 或 m 超过了字符串的长度,则求出来的子串就是从下标 n 开始一直到字符串结束的部分。例如: + * string substr (size_t pos = 0, size_t len = npos) const; +```C++ +string s1 = "this is ok"; +string s2 = s1.substr(2, 4); // s2 = "is i" +s2 = s1.substr(2); // s2 = "is is ok" +``` + ## 2.9 字符串替换 -* replace 成员函数可以对 string 对象中的子串进行替换,返回值为对象自身的引用。例如: +* replace 成员函数可以对 string 对象中的子串进行替换,返回值为对象自身的引用。 + * string (1) string& replace (size_t pos, size_t len, const string& str); + * string& replace (const_iterator i1, const_iterator i2, const string& str); + * substring (2) string& replace (size_t pos, size_t len, const string& str, + size_t subpos, size_t sublen); + * c-string (3) string& replace (size_t pos, size_t len, const char* s); + * string& replace (const_iterator i1, const_iterator i2, const char* s); + * buffer (4) string& replace (size_t pos, size_t len, const char* s, size_t n); + * string& replace (const_iterator i1, const_iterator i2, const char* s, size_t n); + * fill (5) string& replace (size_t pos, size_t len, size_t n, char c); + * string& replace (const_iterator i1, const_iterator i2, size_t n, char c); + * range (6) string& replace (const_iterator i1, const_iterator i2, InputIterator first, InputIterator last); + * initializer list (7) string& replace (const_iterator i1, const_iterator i2, initializer_list il); ```C++ string s1("Real Steel"); @@ -145,65 +190,37 @@ int n = s2.find("OOOOO"); //查找子串 "00000" 的位置,n=2 s2.replace(n, 5, "XXX"); //将子串(n,5)替换为"XXX" cout << s2 < < endl; //输出 HaXXX Potter ``` -## 2.10 字符串删除 -* erase 成员函数可以删除 string 对象中的子串,返回值为对象自身的引用。例如: -```C++ -string s1("Real Steel"); -s1.erase(1, 3); //删除子串(1, 3),此后 s1 = "R Steel" -s1.erase(5); //删除下标5及其后面的所有字符,此后 s1 = "R Ste" -``` -## 2.11 字符串插入 +## 2.10 字符串插入 * insert 成员函数可以在 string 对象中插入另一个字符串,返回值为对象自身的引用。例如: + * string& insert (size_t pos, const string& str); + * string& insert (size_t pos, const string& str, size_t subpos, size_t sublen); + * string& insert (size_t pos, const char* s); + * string& insert (size_t pos, const char* s, size_t n); + * string& insert (size_t pos, size_t n, char c); + * void insert (iterator p, size_t n, char c); + * iterator insert (iterator p, char c); + * void insert (iterator p, InputIterator first, InputIterator last); ```C++ string s1("Limitless"), s2("00"); s1.insert(2, "123"); //在下标 2 处插入字符串"123",s1 = "Li123mitless" s1.insert(3, s2); //在下标 2 处插入 s2 , s1 = "Li10023mitless" s1.insert(3, 5, 'X'); //在下标 3 处插入 5 个 'X',s1 = "Li1XXXXX0023mitless" ``` -## 2.12 字符串流对象 -* 使用流对象 istringstream 和 ostringstream,可以将 string 对象当作一个流进行输入输出。使用这两个类需要包含头文件 sstream。 + +## 2.11 字符串删除 +* erase 成员函数可以删除 string 对象中的子串,返回值为对象自身的引用。如果使用了迭代器。则返回值为指向删除序列后的第一个字符的迭代器。 + * sequence (1)string& erase (size_t pos = 0, size_t len = npos); + * character (2)iterator erase (const_iterator p); + * range (3)iterator erase (const_iterator first, const_iterator last); ```C++ -#include -#include -#include -using namespace std; -int main() -{ - string src("Avatar 123 5.2 Titanic K"); - istringstream istrStream(src); //建立src到istrStream的联系 - string s1, s2; - int n; double d; char c; - istrStream >> s1 >> n >> d >> s2 >> c; //把src的内容当做输入流进行读取 - ostringstream ostrStream; - ostrStream << s1 << endl << s2 << endl << n << endl << d << endl << c < -#include -#include -using namespace std; -int main() -{ - string s("afgcbed"); - string::iterator p = find(s.begin(), s.end(), 'c'); - if (p!= s.end()) - cout << p - s.begin() << endl; //输出 3 - sort(s.begin(), s.end()); - cout << s << endl; //输出 abcdefg - next_permutation(s.begin(), s.end()); - cout << s << endl; //输出 abcdegf - return 0; -} -``` ## 3 字符串转换 ## 3.1 数值转换 @@ -239,11 +256,104 @@ string s("helloworld"); const char * str = s.c_str(); ``` -## 4 string相关的外部算法 +## 4 字符串流对象 +* 将string视为特殊的字符串流。使用流对象的方法处理字符串。 +* 使用流对象 istringstream 和 ostringstream,可以将 string 对象当作一个流进行输入输出。使用这两个类需要包含头文件 sstream。 -> string因为支持迭代器,所以支持所有的容器模板算法。 +```C++ +#include +#include +#include +using namespace std; +int main() +{ + string src("Avatar 123 5.2 Titanic K"); + istringstream istrStream(src); //建立src到istrStream的联系 + string s1, s2; + int n; double d; char c; + istrStream >> s1 >> n >> d >> s2 >> c; //把src的内容当做输入流进行读取 + ostringstream ostrStream; + ostrStream << s1 << endl << s2 << endl << n << endl << d << endl << c < 在正则表达式部分,有专门针对string的正则匹配搜索算法。 + + +## 6 C字符串 +## 7 字符串分割的两种处理方式 + + +## 8 字符串格式化的两种处理方式 + + +## 9 字符串匹配match和查找search的多种实现方法 + +* match整个字符串符合要求 +* search找到符合要求的字符串子串。 + +### 循环暴力查找 + +### 成员函数find查找 + +### 模板函数find查找 + +### 正则表达式匹配 + +## 10 字符串替换的多重实现方法 + +### 暴力替换 +``` + string replaceSpace1(string s) { + string result; + for(int i=0;i 等到以后再处理 - +> 等到以后再处理。 diff --git a/算法/A类:基本算法/5.4 斐波那契数列.md b/算法/A类:基本算法/5.4 斐波那契数列.md new file mode 100644 index 00000000..5b2efcf1 --- /dev/null +++ b/算法/A类:基本算法/5.4 斐波那契数列.md @@ -0,0 +1,62 @@ +# 斐波那契数列 + +## 1 斐波那契数列 + +### 问题描述 + +* 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: +``` +F(0) = 0,   F(1) = 1 +F(N) = F(N - 1) + F(N - 2), 其中 N > 1. +``` +* 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 +* [链接](https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof) + +### 问题分析 + + +### 问题分类 + +* 数组 +* 动态规划+迭代 + +### 选择策略 +* 数组 +* 动态规划 + * 原理: 以斐波那契数列性质 f(n + 1) = f(n) + f(n - 1)f(n+1)=f(n)+f(n−1) 为转移方程。 + +### 算法设计 + +* 状态定义: 设$dp$为一维数组,其中 $dp[i]$ 的值代表 斐波那契数列第 $i$个数字 。 +* 转移方程: $dp[i + 1] = dp[i] + dp[i - 1]$,即对应数列定义 $f(n + 1) = f(n) + f(n - 1)$; +* 初始状态: $dp[0] = 0 dp[1] = 1$,即初始化前两个数字; +* 返回值:$dp[n]$ ,即斐波那契数列的第 n 个数字。 + + +### 算法分析 +* 时间复杂度O(n) +* 空间复杂度O(n) + + +### 算法实现 + +``` + int fib(int n) { + // 递归法,时间复杂度太高。 + if(n==0){ + return 0; + } + if(n==1){ + return 1; + } + // return fib(n-1)+fib(n-2); + long long a[n+1]; + a[0]=0; + a[1]=1; + for(int i=2;i>& board, string word) { + for(int i=0;i> & board,string &word,int row,int col,int k){ + if(row<0 || col <0 ||row>=board.size()||col>=board[0].size())return false; + // cout<& nums) { + for(int i=0;i>& matrix, int target) { + int i = matrix.size() - 1, j = 0; + while(i >= 0 && j < matrix[0].size()) + { + if(matrix[i][j] > target) i--; + else if(matrix[i][j] < target) j++; + else return true; + } + return false; + } +``` + diff --git a/算法/C类:问题类型算法/2.1 反转链表.md b/算法/C类:问题类型算法/2.1 反转链表.md new file mode 100644 index 00000000..215c5411 --- /dev/null +++ b/算法/C类:问题类型算法/2.1 反转链表.md @@ -0,0 +1,85 @@ +# 反转链表 + + +## 1 从尾到头打印链表内容 + +### 问题描述 + +输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 + +### 问题分类 +* 线性数据结构 +* 枚举法 +* 排序问题 + +### 问题分析 + +## 1.1 从尾到头打印链表内容——辅助栈 + +### 策略选择 + +* 数据结构:链表、栈、数组 +* 算法思想:枚举法 +* 可以利用栈的先进后出特性。 +### 算法设计 + + +1. 入栈: 遍历链表,将各节点值 push 入栈。(Python​ 使用 append() 方法,​Java​借助 LinkedList 的addLast()方法)。 +2. 出栈: 将各节点值 pop 出栈,存储于数组并返回。(Python​ 直接返回 stack 的倒序列表,Java ​新建一个数组,通过 popLast() 方法将各元素存入数组,实现倒序输出)。 +### 算法分析 +* 时间复杂度O(n) +* 空间复杂度O(n) + +### 算法实现 + +``` + vector reversePrint1(ListNode* head) { + stack s; + vector v; + ListNode * temp=head; + while(temp){ + s.push(temp->val); + temp=temp->next; + } + while(!s.empty()){ + v.push_back(s.top()); + s.pop(); + } + return v; + } +``` + +## 1.2 从尾到头打印链表内容——递归法 + +### 策略选择 + +* 数据结构:链表 +* 算法思想:枚举法 +* 利用递归后续遍历的特性(子节点在父节点之前除了) + +### 算法设计 + +1. 递推阶段: 每次传入 head.next ,以 head == None(即走过链表尾部节点)为递归终止条件,此时返回空列表 [] 。 +2. 回溯阶段: 利用 Python 语言特性,递归回溯时每次返回 当前 list + 当前节点值 [head.val] ,即可实现节点的倒序输出。 + +### 算法分析 + +* 时间复杂度O(n) +* 空闲复杂度O(n) + +### 算法实现 + +``` + vector reversePrint(ListNode* head) { + vector vec; + rp(head,vec); + return vec; + } + void rp(ListNode* head,vector&vec) { + if(head==nullptr)return ; + rp(head->next,vec); + vec.push_back(head->val); + return ; + } +``` +