目录

1.泛型编程

1.1 模版引入

1.2 模版原理

1.3 模版的优势

2.STL-string

2.1 构造方式

2.2 读写

2.3 迭代器

2.4 length和size接口

2.5 capacity和增容

2.6 字符串拼接

2.7 字符串指定位置插入

2.8 删除子串

3. 简单OJ题

3.1 题目1

3.1.1 思路

3.1.2 代码

3.2 题目2

3.2.1 思路 

3.2.2 代码


1.泛型编程

1.1 模版引入

我们想要交换三种或者更多种不同类型的数字,那么在C语言中需要写这么多个swap函数如下图所示:

C语言不支持函数重载,所以甚至上述的函数名称都得不一样;

// 模版
template<class T> // 或者template<typename T>
void Swap(T& a,T& b) 
{
	T tmp = a;
	a = b;
	b = tmp;
}

1.2 模版原理

当我们调用函数的时候,其实是在调用函数模版实例化生成的对应类型的函数,而不是模版本身;

查看汇编代码能更好地看到这一点

模版本身不会进行编译,只有在调用具体的函数,才会生成模版的实例化对象,才会编译具体的函数,所以模版本身即使有语法错误,只要不调用具体的函数,编译器不会发现模版的语法错误

1.3 模版的优势

回顾一下,我们使用C语言写一个栈存在以下三个问题:

1.需要手动初始化和销毁;

2.没有封装,谁都可以修改结构体的数据;

3.如果想要同时定义两个栈,例如一个栈存int,一个栈存double,根本做不到,因为使用的是typedef进行数据类型的定义;

cpp如何解决这三个问题的呢?

1.使用class就不需要担心初始化和销毁的问题,因为构造函数和析构函数都是自动调用;

2.类中的数据是封装的,使用private限定符,外界不可以随意访问;

3.使用模版进行对象的创建,具体语法如下:

template <class T>
class Stack_cpp
{
private:
    T val;
public:
    Stack_cpp(){};
    ~Stack_cpp(){};
};


int main()
{

    Stack_cpp<int> int_stk;
    Stack_cpp<char> int_stk;
}

2.STL-string

2.1 构造方式

        string其实是一个类,所以类的构造同样适用于string的构造;

#include<iostream>
#include<string>
using namespace std;




int main()
{
    string s1 = "hello"; // 使用赋值号进行构造
    string s2(s1); // 使用string作为形参进行构造
    string s3("hello"); // 使用字符串直接构造
    string s4(s3,1,8); // 将s3的字符从1号位置到8号位置的字符拷贝到s4,但是显然s3不够8个字符,所
                       //以其实就是将s3的1号位置拷贝到结束位置
    string s5(10,'a'); // 10个a作为形参


}

2.2 读写

        由于string对[]进行重载了,所以可以直接使用string s; s[i]对每一个字符串对象进行访问;

返回值是引用类型的,所以可以直接通过返回值进行修改;

string s  = "fuck";
s[3] = 't'; // fuct

2.3 迭代器

可以把string迭代器当做字符指针;其中lst.begin()是字符串的第一个位置,lst.end()是字符串的最后一个位置的后一个位置;

// 迭代器
string lst = "my name is lst";
string::iterator it = lst.begin();
while (it != lst.end())
{
	cout << *it << " ";
	++it;
}

迭代器具有很强的迁移性,其他模版的遍历,迭代器的用法几乎都是一样的;

范围for,其实本质上就是迭代器;

for (auto i : lst) 
{
	cout << i << " ";
}
cout << endl;

反向迭代器,效果和迭代器完全相反,将内容逆置输出;

string::reverse_iterator rit = lst.rbegin();
while (rit != lst.rend()) 
{
	cout << *rit << " ";
	++rit;
}

const迭代器是不能解引用赋值的;只能读不能写;

2.4 length和size接口

都是表示字符串的有效字符的个数,length是在stl之前出现的接口,后来为了和stl其他模版想适应,所以产生了size接口,后面建议使用size接口;

string f = "wocao";
cout << f.size() << endl;

2.5 capacity和增容

        初始容量是15,随着size = capacity,就会进行增容;可以使用对象.capacity()查看目前对象的容量;

        下面可以看到每一次增容的节点数量,大概是上一次的节点数量的1.5倍;

        对象.reserve(需要多少个空间),就会生成多少个空间,例如上面的例子,我可以直接预订100个空间,就不需要频繁的扩容了,此时对象的size和capacity都是100;

        对象.resize()的两种情况;

第一种,直接会缩小size;

第二种size会扩容到20,多出来的会用'x'进行填充;

2.6 字符串拼接

直接使用+=,可以将字符串、字符进行拼接;

使用append(),形参最常用的是插入一个字符串或者字符对象;

string s1 = "123";
string s2 = "456";
s1 += s2;
s1 += "456";
s1.append(s2);
s1.append("456"); 

2.7 字符串指定位置插入

只需要记住下图中标注的两种常用接口即可;

对象.insert(位置,字符串或string对象);

2.8 删除子串

对象.erase(位置,该位置删除的长度如果不填默认删到最后);

3. 简单OJ题

3.1 题目1

仅仅翻转字母

917. 仅仅反转字母 - 力扣(LeetCode)

给你一个字符串 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 <= s.length <= 100
        • s 仅由 ASCII 值在范围 [33, 122] 的字符组成
        • s 不含 '\"' 或 '\\'

        3.1.1 思路

                ①使用两个指针分别指向字符串的首尾,如果不是字母且 begin < end 那就让指针后移(或前移);

                ②两个指针停下来的时候,那么两个指针指向的一定是字母,直接进行交换;

                ③交换完毕之后,两个指针分别后移(或前移);

        3.1.2 代码

        
        bool isAlpha(char c)
        {
            if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') )
            {
                return true;
            }else
            {
                return false;
            }
        }
        
        class Solution {
        public:
            string reverseOnlyLetters(string s) {
                int begin = 0;
                int end = s.size() - 1;
                while(begin < end)
                {
                    // 不是字母就后移
                    while(begin < end && !isAlpha(s[begin]))
                    {
                        ++begin;
                    }
                    while(begin < end && !isAlpha(s[end]))
                    {
                        --end;
                    }
                    swap(s[begin],s[end]);
                    ++begin;
                    --end;
                }
                return s;
            }
        };

        3.2 题目2

        387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

        要求时间复杂度是O(n)

        给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

        示例 1:

        输入: s = "leetcode"
        输出: 0
        

        示例 2:

        输入: s = "loveleetcode"
        输出: 2
        

        示例 3:

        输入: s = "aabb"
        输出: -1
        

        提示:

        • 1 <= s.length <= 105
        • s 只包含小写字母

        3.2.1 思路 

                首先将字符串中的字母全部映射到26个字符中,出现了几次,对应的数字就增加几;建立映射表;

                再遍历一次字符串,查映射表,如果只出现一次,那么就直接返回该字符的下标即可;

        3.2.2 代码

        class Solution {
        public:
            int firstUniqChar(string s) {
                int count[26] = {0};
                // 26个字母映射
                for(int i = 0; i < s.size();++i)
                {
                   ++count[ s[i] - 'a'];
                }
        
                // 找“1”
                for(int i = 0; i < s.size();++i)
                {   
                    if(count[ s[i] - 'a'] == 1)
                    {
                        return i;
                    }
                }
                return -1;
            }
        };

        Logo

        Agent 垂直技术社区,欢迎活跃、内容共建。

        更多推荐