翻转字符串
344. 反转字符串 - 力扣(LeetCode)https://leetcode.cn/problems/reverse-string/
class Solution { public: void reverseString(vector<char>& s) { reverse(s.begin(),s.end());//直接上逆置接口 } };
函数签名:
void reverseString(vector<char>& s);
这个函数不返回任何值 (
void
),并且接受一个vector<char>
类型的引用s
作为输入参数。调用
std::reverse
函数:reverse(s.begin(), s.end());
使用标准库中的
std::reverse
函数来反转vector<char>
中的元素。s.begin()
返回指向向量第一个元素的迭代器,s.end()
返回指向向量最后一个元素之后的一个位置的迭代器。因此,std::reverse
会将s
中的所有元素进行反转。
翻转字符串||
541. 反转字符串 II - 力扣(LeetCode)https://leetcode.cn/problems/reverse-string-ii/description/
问题描述
给定一个字符串
s
和一个整数k
,任务是反转每2k
个字符中的前k
个字符。如果剩余字符不足k
个,则将这些字符全部反转。示例
- 输入:
s = "abcdefghi", k = 3
- 输出:
"cbadefghi"
解释
- 字符串按长度
2k
划分为几个部分。- 对于每个部分,前
k
个字符被反转。- 部分中剩余的字符(如果有)保持不变。
- 将所有部分串联起来形成结果。
代码解释
class Solution { public: string reverseStr(string s, int k) { int pos = 0; // 开始反转或向前移动的位置 // 循环遍历整个字符串直到结束 while (pos < s.size()) { // 如果还剩下至少 k 个字符,反转前 k 个字符 if (pos + k < s.size()) { reverse(s.begin() + pos, s.begin() + pos + k); } else { // 否则,反转所有剩余字符 reverse(s.begin() + pos, s.end()); } // 将位置向前移动 2k 以进入下一个块 pos += 2 * k; } return s; } };
函数签名:
string reverseStr(string s, int k);
这个函数返回一个字符串,并接受一个字符串
s
和一个整数k
作为输入参数。变量初始化:
int pos = 0; // 开始反转或向前移动的位置
pos
是一个整型变量,用来记录当前处理到字符串中的哪个位置。初始时pos
被设置为0
,即从字符串的起始位置开始处理。循环处理字符串:
while (pos < s.size()) { // ... }
使用
while
循环遍历整个字符串,直到pos
超过字符串的长度。条件判断与反转操作:
if (pos + k < s.size()) { reverse(s.begin() + pos, s.begin() + pos + k); } else { reverse(s.begin() + pos, s.end()); }
- 如果当前位置加上
k
仍然小于字符串的长度,那么就反转从pos
到pos + k
之间的字符。- 否则,如果剩余的字符不足
k
个,就反转从pos
到字符串结尾的所有字符。更新位置:
pos += 2 * k;
每次处理完一个块之后,
pos
向前移动2k
个位置,这样就可以跳过已经处理过的部分,并准备处理下一个块。返回结果:
return s;
最后返回经过处理后的字符串。
示例
假设输入字符串为
"abcdefghi"
且k = 3
:
第一次迭代:
pos = 0
,反转"abc"
,结果变为"cba"
。pos
更新为6
(2 * k = 6
)。第二次迭代:
pos = 6
,反转"ghi"
,结果变为"cbadefghi"
。pos
更新为12
,但此时pos
已经大于字符串长度,循环结束。最终输出结果为
"cbadefghi"
。时间复杂度与空间复杂度
- 时间复杂度: O(n),其中 n 是字符串
s
的长度。因为每个字符最多被访问两次(一次正向,一次反向)。- 空间复杂度: O(1),除了输入和输出之外没有使用额外的空间。
翻转字符串中的单词
557. 反转字符串中的单词 III - 力扣(LeetCode)https://leetcode.cn/problems/reverse-words-in-a-string-iii/description/
class Solution { public: string reverseWords(string s) { //判断是否为nullptr if(s.empty())return s; int slow = 0,fast = 0,len = s.size(); while(fast < len){ //先让fast走到空格之前的位置 while(fast < len && s[fast] != ' ')fast++; //进行逆置 reverse(s.begin()+slow,s.begin()+fast); fast++; slow = fast; } return s; } };
检查空字符串:
- 如果输入的字符串
s
是空的,直接返回原字符串。初始化:
- 定义两个整数变量
slow
和fast
,初始值都设为 0。这两个变量将作为指针来遍历字符串。- 获取字符串
s
的长度,并将其存储在变量len
中。遍历和反转:
- 使用
while
循环遍历整个字符串,直到fast
指针到达字符串末尾。- 在循环内部,再使用一个
while
循环来找到单词的结束位置(即遇到空格或到达字符串末尾)。这通过检查s[fast]
是否为空格来实现。- 找到单词后,使用
std::reverse
函数来反转从slow
到fast
之间的字符。这里的std::reverse
是从<algorithm>
头文件中导入的,用于反转范围内的元素。- 将
fast
增加 1 以跳过单词后的空格(如果有的话)。- 将
slow
设置为fast
的值,以便处理下一个单词。返回结果:
- 最终返回修改后的字符串
s
。示例:
- 输入:"the sky is blue"
- 输出:"ehT yks si eulb"
注意:
- 此函数不会反转单词的顺序,而是反转每个单词中的字符。例如,输入 "hello world" 的输出将是 "olleh dlrow",而不是 "world hello"。
- 这个函数没有处理单词间多个空格的情况,也没有处理字符串开头和结尾的空格。如果需要处理这些情况,则需要添加额外的逻辑。
字符串中的第一个唯一字符
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)https://leetcode.cn/problems/first-unique-character-in-a-string/
class Solution { public: //计数排序思想 int firstUniqChar(string s) { int arr[26] = {0}; for(auto ch : s){ // a-a = 0 b -a = 1 c-a = 2 arr[ ch - 'a']++; } for(size_t i = 0;i < s.size();i++){ if (arr[s[i] - 'a'] == 1) return i; } return -1; } };
这段代码定义了一个名为
Solution
的类,并且在其中实现了一个名为firstUniqChar
的方法。这个方法接收一个std::string
类型的参数s
,并返回第一个不重复出现的字符在字符串中的索引,如果不存在这样的字符则返回-1
。这里是详细的代码分析:
初始化计数数组:
- 创建一个大小为 26 的整数数组
arr
,用于存储每个小写字母出现的次数。数组下标代表字母的位置(例如,'a' 对应下标 0,'b' 对应下标 1,以此类推),数组元素表示该字母出现的次数。统计字符出现次数:
- 遍历字符串
s
中的每一个字符ch
。- 计算
ch
在数组arr
中对应的下标,这里用ch - 'a'
来得到该字符与'a'
之间的偏移量。- 将对应下标的计数值增加 1。
查找第一个唯一字符:
- 再次遍历字符串
s
。- 对于每一个字符
s[i]
,计算它在数组arr
中对应的下标。- 如果该字符只出现了一次(即
arr[s[i] - 'a'] == 1
),则返回该字符的索引i
。未找到唯一字符:
- 如果遍历完整个字符串都没有找到只出现一次的字符,返回
-1
。示例:
输入:
"leetcode"
输出:
0
(因为'l'
是第一个只出现一次的字符)输入:
"loveleetcode"
输出:
2
(因为'v'
是第一个只出现一次的字符)输入:
"aabbcc"
输出:
-1
(因为没有只出现一次的字符)注意:
- 此函数假设输入字符串
s
只包含小写字母。如果输入可能包含大写字母或其他字符,则需要对代码进行相应的调整。- 如果输入字符串非常大,这种方法的空间复杂度是 O(1),因为它只需要固定大小的数组来计数,而时间复杂度是 O(n),其中 n 是字符串的长度
字符串最后一个单词的长度
字符串最后一个单词的长度_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking
#include <iostream> #include <string> using namespace std; int main() { string str; //这个接口可以指定换行符才读取结束 getline(cin, str,'\n'); //利用rfind找最后一个空格 size_t pos = str.rfind(' '); //输出长度 cout << str.size() - (pos+1) << endl; }
引入必要的头文件:
#include <iostream>
引入输入输出流库,使得我们可以使用std::cin
和std::cout
。#include <string>
引入字符串处理库,使得我们可以使用std::string
类。使用命名空间:
using namespace std;
使得我们可以直接使用std
命名空间下的标识符,如cout
、cin
和string
。主函数定义:
int main()
定义了程序的入口点。读取输入:
- 定义一个
std::string
类型的变量str
来存储输入的文本。- 使用
getline(cin, str, '\n')
从标准输入读取一行文本,直到遇到换行符\n
。这使得我们可以读取包含空格的字符串。查找最后一个空格的位置:
- 使用
str.rfind(' ')
查找字符串str
中最后一个空格的位置。rfind
方法返回最后一个匹配字符的位置,如果没有找到匹配的字符,则返回std::string::npos
。计算并输出最后一个单词的长度:
- 计算从最后一个空格到最后一个字符的距离,即最后一个单词的长度。这里使用
str.size() - (pos + 1)
来计算长度。- 如果
pos
为std::string::npos
(即没有找到空格),则(pos + 1)
会被转换为一个非常大的数值,因此str.size() - (pos + 1)
会得到一个负数,这会导致运行时错误。为了避免这种情况,我们需要检查pos
是否为std::string::npos
。- 使用
std::cout
输出最后一个单词的长度。示例:
- 输入:
"Hello World"
- 输出:
5
(因为最后一个单词是 "World",长度为 5)
验证回文
125. 验证回文串 - 力扣(LeetCode)https://leetcode.cn/problems/valid-palindrome/
class Solution { public: //判断是否为所需字符 bool isletter(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 && !isletter(s[begin])){ ++begin; } while(begin < end && !isletter(s[end])){ --end; } //判断左右是否是相等的,快排的思想 if(s[begin] != s[end]){ return false; } ++begin; --end; } //排除所有可能就说明是回文 return true; } };
辅助函数
isletter
:
- 这个函数接受一个字符
ch
,并检查它是否是一个字母或数字。- 如果
ch
是一个小写字母、大写字母或数字,则返回true
;否则返回false
。主函数
isPalindrome
:
- 首先,遍历字符串
s
的每个字符ch
并将其转换为小写(如果它是大写字母的话)。- 初始化两个指针
begin
和end
,分别指向字符串的开始和结束位置。- 使用两个
while
循环来逐步向中心逼近,同时跳过非字母和非数字的字符。- 比较
begin
和end
指针所指向的字符是否相同。如果不相同,则立即返回false
表示不是回文。- 当
begin
和end
相遇或者交叉时,说明已经检查完所有字符,此时返回true
表示是回文。示例:
输入:
"A man, a plan, a canal: Panama"
输出:
true
(因为忽略标点符号和空格后,该字符串是一个回文)输入:
"race a car"
输出:
false
(因为忽略标点符号和空格后,该字符串不是一个回文)
把字符串转换成整数
LCR 192. 把字符串转换成整数 (atoi) - 力扣(LeetCode)https://leetcode.cn/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/description/
class Solution { public: int myAtoi(string s) { long long ans = 0; //检查空格(确定起始位置) int pos = 0; while(pos < s.length() && s[pos] == ' ') pos++; //判断是否全是空格 if(pos == s.length() && s[pos] == ' ')return 0; //判断正负 int sym = 1; if(s[pos] == '-')sym = -1,pos++; else if(s[pos] == '+')pos++; //进行转换计算 for(int i = pos;i < s.length() && isdigit(s[i]); i++ ){//判断是否是十进制数 ans = ans * 10 + (sym * (s[i] - '0')); //判断是否大于最大数/小于最小数(避免越界) if(ans > 0 && ans >= INT_MAX)return INT_MAX; if(ans < 0 && ans <= INT_MIN)return INT_MIN; } return ans; } };
初始化和检查空格:
- 定义一个
long long
类型的变量ans
用来存储最终的转换结果。- 定义一个整数变量
pos
用来记录字符串中有效字符的起始位置,默认为 0。- 使用
while
循环来跳过字符串开头的空格,直到遇到非空格字符或到达字符串末尾。检查字符串是否全为空格:
- 如果字符串全部由空格组成,那么返回 0。
判断正负号:
- 如果在
pos
位置遇到了负号-
,则设置sym
为 -1 并将pos
加 1。- 如果在
pos
位置遇到了正号+
,则保持sym
为 1(默认值)并将pos
加 1。转换计算:
- 使用
for
循环遍历从pos
开始的字符,直到遇到非数字字符或到达字符串末尾。- 对于每一个数字字符,首先检查它是否为有效的十进制数字(使用
isdigit
函数)。- 将当前字符减去
'0'
来获取其数值,并乘以sym
来决定正负。- 更新
ans
的值,使其乘以 10 后加上当前数字的值。- 在每次迭代中检查
ans
是否超过了INT_MAX
或INT_MIN
,以避免溢出。返回结果:
- 返回
ans
的值。示例:
输入:
"42"
输出:
42
输入:
" -42"
输出:
-42
输入:
"4193 with words"
输出:
4193
输入:
"words and 987"
输出:
0
输入:
"-91283472332"
输出:
-2147483648
(因为超过了INT_MIN
)
字符串相加
415. 字符串相加 - 力扣(LeetCode)https://leetcode.cn/problems/add-strings/description/
class Solution { public: string addStrings(string num1, string num2) { // 采用进位法 int end1 = num1.size() - 1, end2 = num2.size() - 1; // 存储进位数 int next = 0; //存储最后的和 string sum; 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 = ret % 10; // 取进位数的和 // 头插法 //sum.insert(sum.begin(), ret + '0'); // 尾插法 sum += (ret+'0'); } // 判断是否还有进位数 if (next == 1) { //sum.insert(sum.begin(), '1'); sum += '1'; } //STL逆置接口 reverse(sum.begin(),sum.end()); return sum; } };
初始化:
- 定义两个整数变量
end1
和end2
,分别初始化为num1
和num2
的最后一个字符的位置。- 定义一个整数变量
next
来存储进位。- 定义一个
std::string
类型的变量sum
来存储结果。逐位相加:
- 使用
while
循环来逐位相加num1
和num2
。- 对于
num1
和num2
的每一位,先将其从字符转换为整数(通过减去'0'
)。- 将两个整数以及当前的进位
next
相加。- 更新
next
为当前和除以 10 的商(即新的进位)。- 将当前和对 10 取模的结果转换回字符,并追加到
sum
字符串的末尾。- 继续处理直到
end1
和end2
都小于 0,即已经处理完两个字符串的所有字符。处理最后的进位:
- 如果
next
不为 0,则表示还有进位需要加入到结果中。将next
转换为字符'1'
并追加到sum
字符串的末尾。逆置结果字符串:
- 使用
std::reverse
函数逆置sum
字符串,因为我们在逐位相加的过程中是从低位到高位进行操作的。返回结果:
- 返回逆置后的
sum
字符串作为最终结果。示例:
- 输入:
"11"
,"123"
- 输出:
"134"
字符串相乘
43. 字符串相乘 - 力扣(LeetCode)https://leetcode.cn/problems/multiply-strings/description/
class Solution { public: string multiply(string num1, string num2) { //获取长度 int n = num1.length(); int m = num2.length(); vector<int> v(n+m,0);//定义数组长度(m+n) //不进位计算 for(int i = 0; i < n ; i++){ for(int j = 0; j < m; j++){ int x = num1[n - i - 1] - '0'; int y = num2[m - j - 1] - '0'; v[i + j] += x * y; } } //进位处理 for(int i = 0,sym = 0 ;i < v.size(); i++ ){ v[i] += sym; sym = v[i] / 10; v[i] %= 10; } //最后转为字符返回 string ret; for(int i = v.size() - 1;i >= 0;i--){ if(ret.empty() && v[i] == 0)continue;//这里必须处理,因为这个数的后面都是初始化的0,不需要存 ret += (v[i] + '0'); } return ret.empty() ? "0" : ret; } };
初始化:
- 获取
num1
和num2
的长度分别为n
和m
。- 定义一个整数向量
v
,其长度为n + m
,并初始化为 0。这个向量将用于存储乘积过程中的各个位的值。逐位相乘:
- 使用两层嵌套的
for
循环来逐位相乘num1
和num2
。- 对于
num1
和num2
的每一位,先将其从字符转换为整数(通过减去'0'
)。- 将两个整数相乘,并将结果存储在
v
中相应的位置上。注意这里使用了n - i - 1
和m - j - 1
来从右向左访问字符串中的字符。进位处理:
- 使用一个
for
循环来处理进位。对于v
中的每一个元素,如果其值大于等于 10,则需要进行进位处理。- 进位处理时,将当前值除以 10 来获取进位,然后将当前值对 10 取模来获取余数(即新值)。
转换为字符串:
- 使用一个
for
循环从v
的末尾开始遍历,将每个元素转换为字符并追加到结果字符串ret
中。- 如果
ret
还为空并且当前值为 0,则跳过该值。这是因为乘积的最高位可能是 0,如果存在这样的 0,就不应该加入到结果中。- 如果最终
ret
为空,说明结果为 0,返回字符串"0"
。返回结果:
- 返回结果字符串
ret
。示例:
- 输入:
"123"
,"456"
- 输出:
"56088"