当前位置: 首页 > news >正文

【C++】13.string类的底层

文章目录

  • 3. string类的经典模拟
    • 3.1 浅拷贝
    • 3.2 深拷贝
    • 3.3 模拟实现string
      • 3.3.1 传统版写法的String类
      • 3.3.2 现代版写法的String类
      • 3.3.3 完整代码
    • 3.4 写时拷贝(了解)
    • 3.5string类的模拟实现
  • 4.扩展阅读
  • 5. 牛刀小试
    • 5.1 仅仅反转字母
    • 5.2找字符串中第一个只出现一次的字符
    • 5.3字符串里面最后一个单词的长度
    • 5.4 验证一个字符串是否是回文
    • 5.5字符串相加
    • 5.6 字符串相乘
    • 5.7 把字符串转换成整数
    • 5.8反转字符串 ll
    • 5.9 反转字符串中的单词 lll


3. string类的经典模拟

3.1 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。


3.2 深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

74a91c35ace26ab4f20dbf2b46af4e06


3.3 模拟实现string

3.3.1 传统版写法的String类

class String
{
public:String(const char* str = ""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非法if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s){char* pStr = new char[strlen(s._str) + 1];strcpy(pStr, s._str);delete[] _str;_str = pStr;}return *this;}~String(){if (_str){delete[] _str;         _str = nullptr;     } }
private: char* _str; };

3.3.2 现代版写法的String类

class String {
public: String(const char* str = "") {     if (nullptr == str)     {         assert(false);         return;    }    _str = new char[strlen(str) + 1];     strcpy(_str, str); } String(const String& s)     : _str(nullptr) {     String strTmp(s._str);     swap(_str, strTmp._str); } // 对比下面和上面的赋值那个实现比较好? String& operator=(String s) {     swap(_str, s._str);     return *this; } /* String& operator=(const String& s) {     if(this != &s)     {        String strTmp(s);        swap(_str, strTmp._str);     }    return *this; } */ ~String() {     if (_str)     {delete[] _str;_str = nullptr;}}
private:char* _str;
};

3.3.3 完整代码

string.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1// 防止头文件被多次包含
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;// 命名空间bit,用于封装自定义的string类
namespace bit
{class string{public:// 定义迭代器类型//typedef char* iterator;using iterator = char*;using const_iterator = const char*;//string();// string类的构造函数string(const char* str = "");string(const string& s);string& operator=(const string& s);~string();void reserve(size_t n);// 预留空间void push_back(char ch);// 添加单个字符void append(const char* str);// 追加字符串string& operator+=(char ch);// 重载+=操作符,用于添加单个字符string& operator+=(const char* str);// 重载+=操作符,用于追加字符串// 插入字符或字符串void insert(size_t pos, char ch);void insert(size_t pos, const char* str);// 删除字符或字符串void erase(size_t pos, size_t len = npos);// 查找字符或字符串size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);// 重载[]操作符,用于访问字符char& operator[](size_t i){assert(i < _size);return _str[i];}// 重载[]操作符,用于访问字符(常量版本)const char& operator[](size_t i) const{assert(i < _size);return _str[i];}// 返回迭代器指向字符串的开始和结束iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}// 返回字符串的大小size_t size() const{return _size;}// 返回C风格字符串const char* c_str() const{return _str;}// 清空字符串void clear(){_str[0] = '\0';_size = 0;}// 返回子字符串string substr(size_t pos, size_t len = npos);private:char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;public:// ⴦//static const size_t npos = -1;static const size_t npos;// 静态常量,表示无效位置};// 重载比较运算符bool operator== (const string& lhs, const string& rhs);bool operator!= (const string& lhs, const string& rhs);bool operator> (const string& lhs, const string& rhs);bool operator< (const string& lhs, const string& rhs);bool operator>= (const string& lhs, const string& rhs);bool operator<= (const string& lhs, const string& rhs);ostream& operator<<(ostream& os, const string& str);// 重载输出运算符istream& operator>>(istream& is, string& str);// 重载输入运算符
}

string.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"namespace bit
{// 重定义 string::npos 为 -1const size_t string::npos = -1;// 默认构造函数/*string::string():_str(new char[1]{ '\0' }), _size(0), _capacity(0){}*/// 从 C 风格字符串构造string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}// s2(s1)// 复制构造函数string::string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}// s2 = s1 = s3// s1 = s1;// 赋值操作符string& string::operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}// 析构函数string::~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}// 预留空间void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}// 在末尾添加字符void string::push_back(char ch){/*if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;*/insert(_size, ch);}// 在末尾添加字符串void string::append(const char* str){//size_t len = strlen(str);//if (_size + len > _capacity)//{//	size_t newCapacity = 2 * _capacity;//	// 扩2倍不够,则需要多少扩多少//	if (newCapacity < _size + len)//		newCapacity = _size + len;//	reserve(newCapacity);//}//strcpy(_str + _size, str);//_size += len;insert(_size, str);}// 重载 += 操作符,添加字符string& string::operator+=(char ch){push_back(ch);return *this;}// 重载 += 操作符,添加字符串string& string::operator+=(const char* str){append(str);return *this;}// 在指定位置插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}/*int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];--end;}*/size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;_size++;}// 在指定位置插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){size_t newCapacity = 2 * _capacity;// 扩2倍不够,则需要多少扩多少if (newCapacity < _size + len)newCapacity = _size + len;reserve(newCapacity);}/*int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];--end;}*/size_t end = _size + len;while (end > pos + len - 1){_str[end] = _str[end - len];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}// 删除指定位置的字符void string::erase(size_t pos, size_t len){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{// 从后往前挪size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];++end;}_size -= len;}}// 查找字符size_t string::find(char ch, size_t pos){assert(pos < _size);for (size_t i = pos; i < _size; i++){if (ch == _str[i])return i;}return npos;}// 查找字符串size_t string::find(const char* str, size_t pos){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}// 提取子字符串string string::substr(size_t pos, size_t len){assert(pos < _size);// 大于后面剩余串的长度,则直接取到结尾if (len > (_size - pos)){len = _size - pos;}bit::string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}//cout << sub.c_str() << endl;return sub;}// 重载 == 操作符,比较两个字符串bool operator== (const string& lhs, const string& rhs){return strcmp(lhs.c_str(), rhs.c_str()) == 0;}// 重载 != 操作符bool operator!= (const string& lhs, const string& rhs){return !(lhs == rhs);}// 重载 > 操作符bool operator> (const string& lhs, const string& rhs){return !(lhs <= rhs);}// 重载 < 操作符bool operator< (const string& lhs, const string& rhs){return strcmp(lhs.c_str(), rhs.c_str()) < 0;}// 重载 >= 操作符bool operator>= (const string& lhs, const string& rhs){return !(lhs < rhs);}// 重载 <= 操作符bool operator<= (const string& lhs, const string& rhs){return lhs < rhs || lhs == rhs;}// 重载 << 操作符,用于输出ostream& operator<<(ostream& os, const string& str){//os<<'"';//os << "xx\"xx";for (size_t i = 0; i < str.size(); i++){//os << str[i];os << str[i];}//os << '"';return os;}// 重载 >> 操作符,用于输入istream& operator>>(istream& is, string& str){str.clear();char ch;//is >> ch;ch = is.get();while (ch != ' ' && ch != '\n'){str += ch;ch = is.get();}return is;}
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"// 测试函数1:演示基本操作和迭代器的使用
void test_string1()
{bit::string s2;// 创建一个空的 bit::string 对象cout << s2.c_str() << endl;// 输出空字符串bit::string s1("hello world");// 创建一个包含初始值的 bit::string 对象cout << s1.c_str() << endl;// 输出 "hello world"s1[0] = 'x';// 修改字符串的第一个字符cout << s1.c_str() << endl;// 输出 "xello world"// 使用迭代器遍历字符串for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << " ";// 输出每个字符}cout << endl;// 迭代器 -- 像指针一样的对象// 使用迭代器进行字符修改bit::string::iterator it1 = s1.begin();// 获取迭代器指向字符串开始while (it1 != s1.end()){(*it1)--;++it1;}cout << endl;it1 = s1.begin();// 再次使用迭代器遍历字符串while (it1 != s1.end()){cout << *it1 << " ";// 输出每个字符++it1;}cout << endl;// 修改// 底层是迭代器的支持// 意味着支持迭代器就支持范围for// 使用范围 for 循环修改字符串for (auto& ch : s1){ch++;}// 使用范围 for 循环输出修改后的字符串for (auto ch : s1){cout << ch << " ";}cout << endl;const bit::string s3("xxxxxxxxx");// 使用范围 for 循环遍历 s3 中的每个字符// 由于 s3 是常量,不能修改其内容,因此使用引用 &ch 来遍历for (auto& ch : s3){//ch++;cout << ch << " ";// 输出每个字符}cout << endl;
}// 测试函数2:演示字符串的拼接和插入操作
void test_string2()
{bit::string s1("hello world");cout << s1.c_str() << endl;s1 += '#';// 追加字符s1 += "#hello world";cout << s1.c_str() << endl;bit::string s2("hello world");cout << s2.c_str() << endl;s2.insert(6, 'x');// 在指定位置插入字符cout << s2.c_str() << endl;s2.insert(0, 'x');// 在字符串开始位置插入字符cout << s2.c_str() << endl;bit::string s3("hello world");cout << s3.c_str() << endl;s3.insert(6, "xxx");// 在指定位置插入字符串cout << s3.c_str() << endl;s3.insert(0, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");// 在字符串开始位置插入长字符串cout << s3.c_str() << endl;
}// 测试函数3:演示字符串的删除操作
void test_string3()
{bit::string s1("hello world");cout << s1.c_str() << endl;s1.erase(6, 2);// 删除指定位置的字符cout << s1.c_str() << endl;s1.erase(5, 20);// 删除指定位置的字符,超出字符串长度cout << s1.c_str() << endl;s1.erase(3);// 删除指定位置的字符cout << s1.c_str() << endl;
}void test_string4()// 测试函数4:演示字符串的查找操作
{bit::string s1("hello world");cout << s1.find(' ') << endl;// 查找空格字符的位置cout << s1.find("wo") << endl;// 查找子字符串 "wo" 的位置bit::string s2 = "https://legacy.cplusplus.com/reference/cstring/strstr/?kw=strstr";//bit::string s2 = "https://blog.csdn.net/ww753951/article/details/130427526";size_t pos1 = s2.find(':');// 查找字符 ':' 的位置size_t pos2 = s2.find('/', pos1 + 3);// 查找字符 '/' 的位置,从 pos1 + 3 开始if (pos1 != string::npos && pos2 != string::npos)// 如果都找到了,执行以下操作{bit::string domain = s2.substr(pos1 + 3, pos2 - (pos1 + 3));// 提取域名cout << domain.c_str() << endl;// 输出域名bit::string uri = s2.substr(pos2 + 1);// 提取 URIcout << uri.c_str() << endl;// 输出 URI}
}// 测试函数5:演示字符串的复制和赋值操作
void test_string5()
{bit::string s1("hello world");bit::string s2(s1);// 使用构造函数复制字符串cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1[0] = 'x';// 修改原字符串cout << s1.c_str() << endl;cout << s2.c_str() << endl;// 输出复制的字符串,应保持不变bit::string s3("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx");s1 = s3;// 使用赋值操作符复制字符串cout << s1.c_str() << endl;cout << s3.c_str() << endl;// 输出赋值的字符串,应保持不变s1 = s1;// 自赋值cout << s1.c_str() << endl;
}// 测试函数6:演示字符串的比较和输出操作
void test_string6()
{bit::string s1("hello world");bit::string s2(s1);bit::string s3 = s1;// 构造+拷贝 ->优化直接构造bit::string s4 = "hello world";cout << (s1 == s2) << endl;// 比较两个字符串是否相等cout << (s1 < s2) << endl;// 比较两个字符串的字典序cout << (s1 > s2) << endl;cout << (s1 == "hello world") << endl;// 比较字符串与 C 风格字符串cout << ("hello world" == s1) << endl;//operator<<(cout, s1); // 输出字符串cout << s1 << endl;// 使用重载的 << 运算符输出字符串cin >> s1;// 从标准输入读取字符串cout << s1 << endl;// 输出读取的字符串std::string ss1("hello world");// 使用标准库的 std::stringcin >> ss1;// 从标准输入读取字符串cout << ss1 << endl;// 输出读取的字符串
}int main()
{//test_string1();//test_string2();//test_string3();//test_string4();//test_string5();test_string6();return 0;
}

打印:

test_string1();

4d7caa830b7f62928cdb17b5d3996c4b

test_string2();

eb326610cec1a917c84b39627e51ccae

test_string3();

bcfe37ebe8d16bf33e63dfe00161274a

test_string4();

44a2b1da3a0bb173ebb59753986dd0d2

test_string5();

42f49084063c9891d31d03626f432d63

test_string6();

42f2248db3041c4c62becd0181cc68af


3.4 写时拷贝(了解)

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

写时拷贝

写时拷贝在读取是的缺陷


3.5string类的模拟实现

string模拟实现参考


4.扩展阅读

面试中string的一种正确写法

STL中的string类怎么了?


5. 牛刀小试

5.1 仅仅反转字母

仅仅反转字母

题目:

ba382df063391b0f461bdb0c1498850e

代码:

class Solution {
public:bool isLetter(char ch){if(ch >= 'a' && ch <= 'z')return true;if(ch >= 'A' && ch <= 'Z')return true;return false;}string reverseOnlyLetters(string S) {if(S.empty())return S;size_t begin = 0, end = S.size()-1;while(begin < end){while(begin < end && !isLetter(S[begin]))++begin;while(begin < end && !isLetter(S[end]))--end;swap(S[begin], S[end]);++begin;--end;}return S;}
};

5.2找字符串中第一个只出现一次的字符

找字符串中第一个只出现一次的字符

题目:

b60048cfd46d903f692df278a1a40030

代码:

class Solution {
public:int firstUniqChar(string s){int count[26]={0};// 统计次数for(auto ch :s){count[ch -'a']++;}for(size_t i=0;i < s.size(); ++i){if(count[s[i]-'a']== 1)return i;}return -1;}
};

在这个例子中,for(auto ch : s) 是一个基于范围的循环(range-based for loop),它遍历字符串 s 中的每个字符。auto 关键字告诉编译器自动推断 ch 的类型,这里 ch 将是 char 类型,因为它是从字符串中逐个字符取出的。

代码中,ch 是一个变量,用于在 for 循环中遍历字符串 s 中的每个字符。在 for(auto ch : s) 这行代码中,ch 代表字符串 s 中当前遍历到的字符。

具体来说,这段代码使用了基于范围的循环(range-based for loop),它是一种简洁的遍历容器(如数组、向量、字符串等)的方法。在这个循环中,ch 会依次取得字符串 s 中的每个字符,从第一个字符开始,直到字符串的末尾。

例如,如果字符串 s"hello",那么循环将依次执行如下:

  1. ch 被赋值为 'h'
  2. ch 被赋值为 'e'
  3. ch 被赋值为 'l'
  4. ch 被赋值为 'l'
  5. ch 被赋值为 'o'

每次循环迭代,ch 都会更新为字符串中的下一个字符。在代码中,ch 被用来统计每个字符在字符串中出现的次数。


5.3字符串里面最后一个单词的长度

字符串里面最后一个单词的长度

题目:

661b53cbbeb3f345ec38c0918b5be4ce

代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{string line;
// 不要使用cin>>line,因为会它遇到空格就结束了
// while(cin>>line)while(getline(cin, line))// 使用getline函数读取一行文本,直到遇到换行符{size_t pos = line.rfind(' ');// 使用rfind函数查找最后一个空格的位置cout<<line.size()-pos-1<<endl;// 计算最后一个空格之后的字符数量并输出//例如(0,2)左开右开是1个,2-(0+1)=1//[0,2)左闭右开是2个,2-0=2//(0,2]左开右闭是2个,2-0=2//[0,2]左闭右闭是3个,2-0+1=3//上面是左开右开的情况}return 0;
}

5.4 验证一个字符串是否是回文

验证一个字符串是否是回文

题目:

70b50734e40042edd981dd489fccd3c2

代码:

class Solution {
public:// 判断字符是否为字母或数字bool isLetterOrNumber(char ch){return (ch >= '0' && ch <= '9')|| (ch >= 'a' && ch <= 'z')|| (ch >= 'A' && ch <= 'Z');}// 判断字符串是否为回文bool isPalindrome(string s) {// 先小写字母转换成大写,再进行判断for(auto& ch : s){if(ch >= 'a' && ch <= 'z')ch -= 32;// 将小写字母转换为大写}int begin = 0, end = s.size()-1;// 初始化双指针,分别指向字符串的开始和结束位置while(begin < end)// 当双指针未相遇时继续循环{while(begin < end && !isLetterOrNumber(s[begin]))// 移动左指针,直到它指向字母或数字++begin;while(begin < end && !isLetterOrNumber(s[end]))// 移动右指针,直到它指向字母或数字--end;if(s[begin] != s[end])// 比较左右指针指向的字符是否相等{return false;// 如果不相等,说明不是回文}else{++begin; // 如果相等,移动指针继续比较--end;}}return true;// 如果所有字符都相等,说明是回文}
};

注意:

我们要实现的是:给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false

而:如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。这个东西是回文串的描述,不需要实现!


5.5字符串相加

字符串相加

题目:

052106feb64e3d520dd5b6fffc35762b

代码:

class Solution {
public:// 将两个字符串形式的数字相加string addStrings(string num1, string num2) {string str;// 用于存储最终的相加结果int end1=num1.size()-1,end2=num2.size()-1;// 两个字符串的末尾索引int next=0;// 用于存储进位值// 循环处理两个字符串的每一位数字while(end1>=0 || end2>=0){int x1=end1>=0?num1[end1]-'0':0;// 获取num1当前位的数字,如果已经遍历完则为0int x2=end2>=0?num2[end2]-'0':0;// 获取num2当前位的数字,如果已经遍历完则为0--end1;// 移动到num1的前一位--end2;// 移动到num2的前一位int ret = x1+x2+next;// 计算当前位的和加上进位next=ret/10;// 计算新的进位值ret=ret%10;// 计算当前位的结果// 将当前位的结果插入到结果字符串的开头str.insert(str.begin(), '0'+ret);//str.insert(0,1,'0'+ret);// 这行代码与上面一行功能相同,但注释掉的这行代码是另一种插入方式}// 如果最后还有进位,需要将进位值添加到结果字符串的开头if(next==1){str.insert(str.begin(), '1');}return str;// 返回最终的相加结果}
};

5.6 字符串相乘

43. 字符串相乘 - 力扣(LeetCode)

题目:

5fb6c8eec02d8bdab7649ad4cce80fc2

代码:

class Solution 
{
public:void MulItem(string &tmp, string &num1, char a){int i = 0, sign=0;int mul = 0;while(i < num1.size()){mul = (num1[i]-'0') * (a-'0') + sign;if(mul >= 10){sign = mul / 10;mul %= 10;}elsesign = 0;tmp.push_back(mul+'0');i++;}    if(sign > 0)tmp.push_back(sign+'0'); }   //对应为相加,sign进位采用引用传递int AddItem(int a, int b, int &sign){int add = a+b+sign;if(add >= 10){sign = 1;add -= 10;}elsesign = 0;return add;}//错位相加void MoveAdd(string &result, string &tmp, int k){int i, j;i = k;j = 0;int sign = 0;while(i<result.size() &&j<tmp.size()){result[i] = AddItem(result[i]-'0', tmp[j]-'0', sign) + '0';i++;j++;}while(i<result.size() && sign){result[i] = AddItem(result[i]-'0', 0, sign)+'0';i++;}while(j < tmp.size()){int v = AddItem(0, tmp[j]-'0', sign);result.push_back(v+'0');j++;}if(sign)result.push_back(sign+'0');}string multiply(string num1, string num2) {//先翻转数据,方便进位处理reverse(num1.begin(), num1.end());reverse(num2.begin(), num2.end());string tmp, result;for(int i=0; i<num2.size(); ++i){//使用num2的每一个数据乘以num1MulItem(tmp, num1, num2[i]);//将乘得的结果进行错位相加MoveAdd(result, tmp, i);tmp.clear();}    while(result.size()!=1 && result.back()=='0')result.pop_back();//翻转数据,恢复数据reverse(result.begin(), result.end());return result;}
};

5.7 把字符串转换成整数

LCR 192.把字符串转换成整数(atoi)

题目:

25b74782239d0f71bd733eec137d001e

代码:

class Solution {
public:int myAtoi(string str) {bool sign = true;   //默认为正数// 跳过开头可能存在的空格int i = 0;while(i < str.size() && str[i] == ' ') {i++;}//接着判断首个字符是否为正负号if(str[i] == '-') {sign = false;  // 该字符串为负数,移至下一个字符接着判断i++;          }else if(str[i] == '+')  // 字符串为正数,sign已经默认为true,直接移动到下一位即可i++;   //下面开始对非正负符号位进行判断if(str[i] < '0' || str[i] > '9') // 正常数字第一位不能是0,必须为1~9之间的数字,否则就是非法数字return 0;  int res = 0;   //这里res用的int型,需要更加仔细考虑边界情况,但如果用long的话可以省去一些麻烦int num = 0; int border = INT_MAX / 10;  // 用来验证计算结果是否溢出int范围的数据while(i < str.size()){// 遇到非数字字符,则返回已经计算的res结果if(str[i] < '0' || str[i] > '9') break;// 注意这句话要放在字符转换前,因为需要验证的位数比实际值的位数要少一位, 这里比较巧妙的地方在于// 1. 用低于int型数据长度一位的数据border判断了超过int型数据长度的值 // 2. 将超过最大值和低于最小值的情况都包括了if(res > border || res == border && str[i] > '7')  return sign == true ? INT_MAX : INT_MIN;//开始对数字字符进行转换num = str[i] - '0';res = res * 10 + num;i++;}//最后结果根据符号添加正负号return sign == true ? res : -res;}
};

5.8反转字符串 ll

541.反转字符串 ll

题目:

7088baf973ac224db064dc52bbad997e

代码:

class Solution {
public:string reverseStr(string s, int k) {for(int i=0;i<s.size();i+=2*k){if(i+k<=s.size()){reverse(s.begin()+i,s.begin()+i+k);}else{reverse(s.begin()+i,s.end());}}return s;}
};

5.9 反转字符串中的单词 lll

557.反转字符串中的单词 lll

题目:

163713fea159122c6ab40a2a3439b7f9

代码:

class Solution {
public:void Reverse(string &s, int start, int end){char tmp;while(start < end){tmp = s[start];s[start] = s[end];s[end] = tmp;start++;end--;}}string reverseWords(string s) {size_t start = 0;size_t end = 0;while(start < s.size()){end = s.find(' ', start);if(end == string::npos){end = s.size();break;}Reverse(s, start, end-1);start = end+1;}Reverse(s, start, end-1);return s;}
};

http://www.mrgr.cn/news/54818.html

相关文章:

  • C++ 异步执行任务async()(补充)
  • idea 2023 创建 springboot 项目 LTS
  • 【python写一个带有界面的计算器】
  • docker-compose安装
  • 关于鸿蒙学习之遇到的问题——ERROR: Invalid dependency entry
  • 电子商务网站维护技巧:保持WordPress、主题和插件的更新
  • 机器学习与神经网络:科技的星辰大海
  • 关于WPF项目降低.Net版本
  • java分页遍历
  • C# 条形码、二维码标签打印程序
  • git分支操作简记
  • 设计模式总结
  • vscode默认添加python项目的源目录路径到执行环境(解决ModuleNotFoundError: No module named问题)
  • debug:vscode使用ssh连接
  • pycharm调试带参数命令行的程序
  • Linux批量创建多个文件
  • 淘系商品详情数据接口系列的详细介绍
  • 推荐一款非常好用的3d设计软件:LuBan 3D
  • 基于opencv的人脸闭眼识别疲劳监测
  • Eclipse——Java开发详解
  • java基本数据类型
  • 自动对焦爬山算法原理
  • MySQL数据库备份和恢复:全面指南与实战代码
  • 【算法】KMP字符串匹配算法
  • MySQL-28.事务-介绍与操作
  • ElasticSearch-7.17.24设置密码及CA证书