图源:文心一言
上机题目练习整理~🥝🥝
本篇作为字符串的代码补充,提供了3种(差别并不大)解法以及函数的详细解释,供小伙伴们参考~🥝🥝
前文:🌸数据结构04:串的存储结构与KMP算法_串的三种存储方式-CSDN博客
- 第1版:在力扣新手村刷题的记录,方法一与方法二是 文心一言 老师提供的建议,方法三是力扣的官方解法~🧩🧩
编辑:梅头脑🌸
题目:709. 转换成小写字母 - 力扣(LeetCode)
📇目录
🧵转换小写字母的题目
🧩题目
🌰方法一:for循环 + 转小写函数tolower
🌰方法二:transform转换 + 转小写函数tolower
🌰方法三:for循环 + ASCII码
🔚结语
🧵转换小写字母的题目
🧩题目
给你一个字符串
s
,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。示例 1:
输入:s = "Hello" 输出:"hello"示例 2:
输入:s = "here" 输出:"here"示例 3:
输入:s = "LOVELY" 输出:"lovely"
🌰方法一:for循环 + 转小写函数tolower
📇算法思路
- 算法思想:使用for循环,对于字符串中的每个字母转小写~
- 时间复杂度:O(n),其中n是数组的长度,该代码对字符串中的每个字符都进行了操作。
- 空间复杂度:O(1),其中n是数组的长度,该代码直接在原字符串上进行操作,没有使用额外的存储空间。
⌨️算法代码
class Solution {
public:
string toLowerCase(string s) { // 返回类型为string的方法,名为toLowerCase。它接受一个名为s的字符串参数
for (char &c : s) { // 基于范围的for循环,用于遍历字符串s中的每一个字符。这里使用的是C++11中的范围for循环语法
c = std::tolower(c); // 对于字符串s中的每个字符c,都调用了std::tolower函数。这个函数是C++标准库中的一个函数,用于将大写字母转换为小写字母
}
return s; // 返回转换后的字符串 // 返回原始字符串s
}
};
⌨️温馨提示
可能问题:请注意,以下写法可能会导致下图的执行错误:
- 第4行直接写为:“for (char c : s)”,而非for (char &c : s)
- 第5行直接写为:“std::tolower(c);”,而非c = std::tolower(c);
问题所在:由于
std::tolower(c);
没有将结果存储回原字符c
,所以实际上有些字符未被转换为小写。因此,当您尝试返回原始字符串时,它仍然是原来的大小写形式。
由于
std::tolower(c);
没有将结果存储回原字符c
,所以实际上有些字符未被转换为小写。因此,当您尝试返回原始字符串时,它仍然是原来的大小写形式。
基于范围的for循环(Range-based for loop)
是C++11中引入的一种新特性,它允许我们更简洁、更直观地遍历容器(如数组、字符串、向量等)中的元素。
这种循环的基本语法如下:
for (element_type value : container) {
// 循环体
}
element_type
是容器中元素的类型,value
是我们为每个元素定义的临时变量名,container
是要遍历的容器。
为什么使用基于范围的for循环?
- 简洁性:它避免了使用传统的迭代器,使代码更简洁。
- 直观性:对于不熟悉迭代器的开发者来说,基于范围的for循环更直观,更容易理解。
- 性能:在某些情况下,基于范围的for循环可能比使用迭代器更快,因为编译器可以进行更多的优化。
例子:
假设我们有一个整数数组,并想打印出数组中的所有元素:
使用传统的迭代器:
#include <iostream>
int main() {
int arr[] = {1, 2, 3, 4, 5};
for (int *it = arr; it != arr + 5; ++it) {
std::cout << *it << ' ';
}
return 0;
}
使用基于范围的for循环:
#include <iostream>
int main() {
int arr[] = {1, 2, 3, 4, 5};
for (int value : arr) {
std::cout << value << ' ';
}
return 0;
}
基于范围的for循环不仅适用于数组,还适用于所有支持迭代器的容器,如std::vector
, std::string
, std::list
等。
例如本题就是基于std::string
的遍历~~
🌰方法二:transform转换 + 转小写函数tolower
📇算法思路
- 算法思想:将循环替换为transform,也可以达到对字符串中的字符逐个操作的结果;
- 时间复杂度:O(n),其中n是数组的长度,该代码对字符串中的每个字符都进行了操作。
- 空间复杂度:O(1),其中n是数组的长度,该代码直接在原字符串上进行操作,没有使用额外的存储空间。
⌨️算法代码
class Solution {
public:
string toLowerCase(string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower); // 将所有字符转换为小写
return s; // 返回转换后的字符串
}
};
std::transform
: 这是C++标准库中的函数,用于对容器中的元素进行转换。s.begin(), s.end()
: 这两个参数定义了一个范围,即从字符串s
的开始到结束。这意味着我们要对字符串s
中的所有字符进行操作。s.begin()
: 这是输出迭代器,表示转换后的字符应该被写入的位置。因为我们要将转换后的字符覆盖原字符串,所以输出迭代器就是s.begin()
。::tolower
: 这是一个函数指针,指向C标准库中的tolower
函数。这个函数的作用是将大写字母转换为小写字母。
⌨️知识扩展
transform
参考原文:C++ transform(STL transform)函数用法详解 (biancheng.net)
transform() 可以将函数应用到序列的元素上,并将这个函数返回的值保存到另一个序列中,它返回的迭代器指向输出序列所保存的最后一个元素的下一个位置。
- 这个序列可以是字符串,如本题;
- 这个序列可以是向量容器,例如以下举栗在向量中存储的数据 从 摄氏度转换到 华氏度。
std::vector<double> deg_C {21.0, 30.5, 0.0, 3.2, 100.0}; std::vector<double> deg_F(deg_C.size()); std::transform(std::begin(deg_C), std::end(deg_C), std::begin(deg_F),[](double temp){ return 32.0 + 9.0*temp/5.0; }); //Result 69.8 86.9 32 37.76 212
- 第1行代码创建了一个名为
deg_C
的向量,并初始化了五个浮点数;- 第2行代码创建了一个新的向量
deg_F
,其大小与deg_C
相同。这个新向量被初始化为空。- 第3行使用了
std::transform
算法来转换deg_C
中的数据,并将结果存储在deg_F
中。
std::begin(deg_C)
和std::end(deg_C)
:这两个函数是定义输入序列的输入迭代器,指向deg_C
向量的开始和结束。std::begin(deg_F)
:是目的位置的第一个元素的输出迭代器,指向deg_F
向量的开始。(值得注意的是,如果是rbegin,则为反向迭代器,指向容器中的最后一个元素)[](double temp){ return 32.0 + 9.0*temp/5.0; }
:这是一个 lambda 函数,用于将摄氏度转换为华氏度。转换公式是:F = C × 9/5 + 32。
上述代码感兴趣可以直接运行这个:
#include <iostream>
#include <vector>
#include <algorithm> // 为了使用 std::transform
int main() {
std::vector<double> deg_C {21.0, 30.5, 0.0, 3.2, 100.0};
std::vector<double> deg_F(deg_C.size());
std::transform(std::begin(deg_C), std::end(deg_C), std::begin(deg_F), [](double temp) { return 32.0 + 9.0 * temp / 5.0; });
// 打印转换结果
for (const auto& temp : deg_F) {
std::cout << temp << " ";
}
return 0;
}
用静态数组也可以,不过文心老师温馨提醒,实际使用过程中,数组长度一般是固定的,灵活性小于容器,且不负责内存管理~
#include <iostream>
int main() {
double deg_C[] = {21.0, 30.5, 0.0, 3.2, 100.0};
double deg_F[5]; // 注意大小固定为5
for (size_t i = 0; i < 5; ++i) {
deg_F[i] = 32.0 + 9.0 * deg_C[i] / 5.0;
}
// 打印转换结果
for (size_t i = 0; i < 5; ++i) {
std::cout << deg_F[i] << " ";
}
return 0;
}
🌰方法三:for循环 + ASCII码
📇算法思路
- 算法思想:
- ASCII码中,小写字母a-z的码值为97-122。因此,要将大写字母A-Z转换为小写字母,只需将对应的大写字母码值加上32即可;
- 例如,大写字母A的码值为65,转换为小写字母a的码值为97(65+32);
图源:java数据类型转换_java里面long转换对应的ascii码-CSDN博客
⌨️算法代码
class Solution {
public:
string toLowerCase(string s) {
for (char& ch: s) {
if (ch >= 65 && ch <= 90) { // 如果字符为大写,即ASCII码介于65-90
ch |= 32; // 对 ch 的 ASCII码与 32 做按位或运算,替代与 32的加法运算。
}
}
return s;
}
};
作者:力扣官方题解
来源:https://leetcode.cn/problems/to-lower-case/solutions/1151839/zhuan-huan-cheng-xiao-xie-zi-mu-by-leetc-5e29/
⌨️算法解释
第6行完全可以使用 ch = ch + 32;而官方采用了按位或运算ch |= 32,这么修改的条件如下:
- 正好[65,90] 对应的二进制表示为 [(01000001)2,(01011010)2],观察从高到低第3位恒为0;
- 32对应的二进制为(00100000)2,观察从高到低第3位恒为1;
- 0和1相与刚好就是相加的意思,对于这道题,可以用或代替相加的功能;
- 不晓得是不是业内主流做法,因为按位与比相加快很多;相反,如果不能保证被加数与加数的相应位数刚好错开,就不能这么玩了。
🔚结语
博文到此结束,写得模糊或者有误之处,欢迎小伙伴留言讨论与批评,督促博主优化内容{例如有错误、难理解、不简洁、缺功能}等,博主会顶锅前来修改~~😶🌫️😶🌫️
我是梅头脑,本片博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下,感谢点赞小伙伴对于博主的支持~~🌟🌟
同系列的博主博文在以下链接~~🌸🌸
数据结构_梅头脑_的博客-CSDN博客https://blog.csdn.net/weixin_42789937/category_12262100.html?spm=1001.2014.3001.5482