自学内容网 自学内容网

【C++力扣】917.仅仅反转字母|387.字符串中第一个唯一字符|415.字符串相加


Blog’s 主页: 白乐天_ξ( ✿>◡❛)
🌈 个人Motto:他强任他强,清风拂山冈!
🔥 所属专栏:C++深入学习笔记
💫 欢迎来到我的学习笔记!

一、917.仅仅反转字母

1.1 题目描述

给你一个字符串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 不含 '\"' '\\'
只反转字母,不反转特殊符号,相当于忽略掉特殊字符,首尾交换。

1.2 分析过程

想法一:使用迭代器:

  1. 一个正向迭代器指向开始位置;
  2. 一个反向迭代器指向结束位置;
  3. 缺点:正向迭代器与反向迭代器不能做比较,因为类型不相同。类型如下:
cout << "string::iterator" << typeid(string::iterator).name() << endl;
cout << "string::reverse_iterator" << typeid(string::reverse_iterator).name() << endl;

//string::iteratorclass std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >
//string::reverse_iteratorclass std::reverse_iterator<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > > >

想法二:使用两个正向迭代器即使用下标;不能使用范围for,因为底层就是迭代器。

  1. 避免一个字母都没有的情况:加上一个left < right条件;
  2. 避免死循环不懂的情况: swap(s[left++], s[right--]);交换以后继续往两边走。

1.3 代码解答

class Solution
{
public:
// 判断字符是不是字母
bool isLetter(char ch)
{
if (ch >= 'a' && ch <= 'z')
return true;
else if (ch >= 'A' && ch <= 'Z')
return true;
else
return false;
}
// 使用下标进行遍历:
string reverseOnlyLetters(string s)
{
int left = 0;
int right = s.size() - 1;// size表示最后一个字符串的下一个位置
while (left < right)
{
while (left < right && !isLetter(s[left]))// left < right条件可以
{
++left;// 往右边走
}
while (left < right && !isLetter(s[right]))
{
--right;// 往左边走
}
swap(s[left++], s[right--]);// 交换,为什么++、--?避免死循环,不往后走,因此交换完后,left继续往右、right继续往左!否则他们两个就不动了
}
return s;
}
};

二、387.字符串中第一个唯一字符

7月20日3:02:00

2.1 题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

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

2.2 分析过程以及代码实现

  1. 方法一
  • 时间复杂度:O(N<sup>2</sup>);(不优)
  • 每个字符都与其他字符对比一遍。
  1. 方法二:计数排序
  • 时间复杂度:O(N)
  • 统计每个字符出现的次数,返回只第一个只出现一次的字符的索引(即下标)。
  • 实现:
class Solution
{
public:
int firstUniqChar(string s)
{
// 使用相对映射的方法:进行计数排序
int count[26] = { 0 };
// 统计次数
for (auto ch : s)// 使用范围for进行遍历
{
count[ch - 'a']++;// ????
// 这里是要统计字符串s中的字符到26个小写字母里面去,有多少个字符,26个字母中就会出现对应的次数
}
// 这里就是用下标访问,而不是范围for
for (size_t i = 0; i < s.size(); ++i)
{
if (count[s[i] - 'a'] == 1)// 说明它只出现了一次,而且是第一个只出现一次的字符
return i;
}
return -1;// 说明s字符串中的都是重复出现的
}
};

三、415.字符串相加

7月20日3:10:00

3.1 题目描述

给定两个字符串形式的非负整数 num1num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

示例 1:

输入:num1 = "11", num2 = "123"
输出:"134"

示例 2:

输入:num1 = "456", num2 = "77"
输出:"533"

示例 3:

输入:num1 = "0", num2 = "0"
输出:"0"

提示:
● 1 <= num1.length, num2.length <= 104
● num1 和num2 都只包含数字 0-9
● num1 和num2 都不包含任何前导零

3.2 分析过程

想法一:error

  • 当整型数据很大时,即使是long long类型也可能存储不下,就会使用字符串进行存储、运算。然后使用字符串模拟四则运算,这就是所谓的“大数运算”。本题模拟的是加法运算。
  • 字符串转换成整型:stoi;各种类型转换成字符串:to_string
  • 但是这种方法不行,转换后数据不仅超出表示范围,而且还会丢失!

想法二:right

  • 字符串中的字符倒着取,从末尾开始进行运算;
  • 只要内存足够,字符串存储在内存中是一定能存储下的;(例如:整数长度100万,也就是内存空间大约1MB)
  • 字符串要两个都结束了才是结束,短字符串结束时长字符串是需要继续的,例如:"9999999999999999" + "1",它不断地都有进位的,不能直接将前几位字符数据拷贝下来。
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 val1 = end1 >= 0 ? num1[end1] - '0' : 0;
int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
end1--;
end2--;
int ret = val1 + val2 + next;// 加上进位
next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
ret = ret % 10; 
// 将最终的结果进行头插到str中:(不太好)
            // 不断头插n次时,时间复杂度就已经O(N)了
str.insert(str.begin(), '0' + ret);
}
if (next == 1)
str.insert(str.begin(), '1');
return str;
}
};

3.3 代码实现

写法一:使用头插

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 val1 = end1 >= 0 ? num1[end1] - '0' : 0;
int val2 = end2 >= 0 ? num2[end2] - '0' : 0;
end1--;
end2--;
int ret = val1 + val2 + next;// 加上进位
next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
ret = ret % 10; 
// 将最终的结果进行头插到str中:(不太好)
            // 不断头插n次时,时间复杂度就已经O(N)了
str.insert(str.begin(), '0' + ret);
}
if (next == 1)
str.insert(str.begin(), '1');
return str;
}
};

写法二:使用尾插

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 val1 = end1 >= 0 ? num1[end1] - '0' : 0;
int val2 = end2 >= 0 ? num2[end2] - '0' : 0;

int ret = val1 + val2 + next;// 加上进位
next = ret / 10;// 记下进位数:ret大于10,记下1;ret小于10,记下0
ret = ret % 10;

str += ('0' + ret);// 尾插,这里是operator+=的一种用法,O(N)
}
if (next == 1)
str += '1';// 结果是倒着的,就需要进行逆置:即使用算法库里面的reverse,但是要求是双向迭代器
reverse(str.begin(), str.end());

return str;
}
};


原文地址:https://blog.csdn.net/lusanjiu/article/details/142726900

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!