给你一个字符串
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
不含'\"'
或'\\'
class Solution {
public:
bool isLeeter(char ch) {
if (ch >= 'a' && ch <= 'z') {
return true;
}
if (ch >= 'A' && ch <= 'Z') {
return true;
}
return false;
}
string reverseOnlyLetters(string s) {
size_t begin = 0, end = s.size() - 1;
while (begin < end) {
while (begin < end && !isLeeter(s[begin]))
begin++;
while (begin < end && !isLeeter(s[end]))
end--;
swap(s[begin], s[end]);
begin++;
end--;
}
return s;
}
};
isLeeter 函数
isLeeter
是一个辅助函数,用于判断给定的字符ch
是否为字母(大写或小写)。它通过检查ch
是否位于'a'
到'z'
或'A'
到'Z'
的范围内来实现这一点。如果ch
是字母,函数返回true
;否则返回false
。
reverseOnlyLetters 函数
reverseOnlyLetters
函数接受一个字符串s
作为参数,返回一个新字符串,其中s
中的所有字母都被反转,而非字母字符保持原位。
这个函数使用了两个指针(或索引)begin
和end
,分别指向字符串的开始和结束。然后,它进入一个循环,其中:
首先,它使用isLeeter
函数检查begin
指向的字符是否不是字母,如果是,begin
就向右移动,直到它指向一个字母或超过end
。
类似地,它检查end
指向的字符,如果不是字母,end
就向左移动,直到它指向一个字母或小于begin
。
一旦begin
和end
都指向字母,就交换这两个位置的字符,并将begin
向右移动一位,将end
向左移动一位。
这个过程一直进行,直到begin
大于或等于end
为止,这意味着所有的字母都已经检查并在需要时进行了反转。
给定一个字符串
s
,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回-1
。示例 1:
输入: s = "leetcode" 输出: 0
示例 2:
输入: s = "loveleetcode" 输出: 2
示例 3:
输入: s = "aabb" 输出: -1
提示:
1 <= s.length <= 10(5)
s
只包含小写字母
class Solution {
public:
int firstUniqChar(string s) {
int Count[26];
for(auto x:s){
Count[x-'a']++;
}
for(int i=0;i
定义字符计数数组
int Count[26];
这行代码定义了一个整型数组Count
,大小为26,用于存储字符串s
中每个字母出现的次数。数组的每个元素对应英文字母表中的一个字母,即Count[0]
对应字母'a'
的出现次数,Count[25]
对应字母'z'
的出现次数。注意,这里假设字符串s
只包含小写英文字母。
计数循环
for(auto x:s){ Count[x-'a']++; }
这个循环遍历字符串s
中的每个字符x
。对于每个字符,它通过x-'a'
计算出字符x
相对于'a'
的偏移量,这个偏移量即为数组Count
中对应的索引。然后,它通过Count[x-'a']++
递增这个索引处的值,从而计算出每个字母在字符串中出现的次数。
检查第一个唯一字符
for(int i=0;i
s
,从头开始检查每个字符。对于每个字符s[i]
,它同样计算出相对于'a'
的偏移量,并在Count
数组中查找这个偏移量对应的出现次数。如果某个字符的出现次数等于1(Count[s[i]-'a']==1
),这意味着这个字符是唯一的(不重复的),函数立即返回这个字符的索引i
。
没有找到唯一字符
如果函数能够完成上述循环而没有返回任何索引,这意味着字符串中没有不重复的字符。因此,函数最后返回-1
,表示没有找到不重复的字符。
时间复杂度与空间复杂度
这种方法的空间复杂度为O(1)(因为Count
数组的大小是固定的),时间复杂度为O(n),其中n是字符串的长度。
描述
计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)
输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。
输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。
示例1
输入:
hello nowcoder
输出:
8
说明:
最后一个单词为nowcoder,长度为8
#include
#include
using namespace std;
int main() {
string s;
getline(cin, s);
int pos=s.rfind(' ');
string sub=s.substr(pos+1);
cout<
getline
和 cin
的区别
getline
和 cin
都是C++中用于从标准输入读取用户输入的方法,但它们有一些重要的区别:
数据类型:
cin
通常用于从标准输入读取基本数据类型,如整数、浮点数、字符等。
getline
主要用于读取文本行,通常用于读取字符串。
分隔符:
cin
通过空格、制表符或换行符来分隔输入,它会在空白字符前停止读取。
getline
会读取整行文本,包括换行符,直到遇到换行符为止。因此,它可以读取包含空格的完整文本行。
处理空格:
cin
遇到空格时会停止读取,因此无法读取包含空格的字符串。
getline
能够处理包含空格的文本,因为它会一直读取到换行符为止。
#include
#include
int main() {
std::string line;
std::cout << "Enter a line of text: ";
std::getline(std::cin, line);
std::cout << "You entered: " << line << std::endl;
return 0;
}
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串
s
,如果它是 回文串 ,返回true
;否则,返回false
。示例 1:
输入: s = "A man, a plan, a canal: Panama" 输出:true 解释:"amanaplanacanalpanama" 是回文串。
示例 2:
输入:s = "race a car" 输出:false 解释:"raceacar" 不是回文串。
示例 3:
输入:s = " " 输出:true 解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。 由于空字符串正着反着读都一样,所以是回文串。
提示:
1 <= s.length <= 2 * 10(5)
s
仅由可打印的 ASCII 字符组成
class Solution {
public:
bool isLeeterOrNumber(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9');
}
bool isPalindrome(string s) {
for (auto& x : s)
if (x >= 'A' && x <= 'Z')
x = x + 32;
int begin = 0, end = s.size() - 1;
while (begin < end) {
while (begin < end && !isLeeterOrNumber(s[begin])) {
begin++;
}
while (begin < end && !isLeeterOrNumber(s[end])) {
end--;
}
if (s[begin] != s[end])
return false;
begin++;
end--;
}
return true;
}
};
isLeeterOrNumber
函数:
这是一个辅助函数,用于检查给定字符是否是字母(大小写)或数字。
函数返回 true
如果字符是字母(小写或大写)或数字,否则返回 false
。
isPalindrome
函数:
这个函数接受一个字符串 s
作为输入参数,用于判断该字符串是否是回文串。
在函数内部,首先将字符串中的大写字母转换为小写字母,这是为了使字符串中的字母不区分大小写。
然后,使用两个指针 begin
和 end
分别指向字符串的开头和结尾。
进入一个循环,该循环会在 begin
小于 end
时执行,因为我们只需要比较一半的字符。
在循环中,首先通过两个内部循环移动 begin
和 end
指针,直到它们指向字母或数字。这是为了跳过非字母和非数字的字符。
一旦两个指针指向字母或数字,它们会比较指向的字符是否相同。如果不相同,函数会立即返回 false
,表示字符串不是回文串。
如果相同,begin
指针向后移动一步,end
指针向前移动一步,然后继续比较下一对字符。
如果在整个循环过程中都没有发现不同的字符,那么字符串被认为是回文串,函数返回 true
。
给定两个字符串形式的非负整数
num1
和num2
,计算它们的和并同样以字符串形式返回。你不能使用任何內建的用于处理大整数的库(比如
BigInteger
), 也不能直接将输入的字符串转换为整数形式。示例 1:
输入:num1 = "11", num2 = "123" 输出:"134"
示例 2:
输入:num1 = "456", num2 = "77" 输出:"533"
示例 3:
输入:num1 = "0", num2 = "0" 输出:"0"
提示:
1 <= num1.length, num2.length <= 10(4)
num1
和num2
都只包含数字0-9
num1
和num2
都不包含任何前导零
class Solution {
public:
string addStrings(string num1, string num2) {
int end1 = num1.size() - 1;
int end2 = num2.size() - 1;
int value1 = 0, value2 = 0, next = 0;
string addret;
while (end1 >= 0 || end2 >= 0) {
if (end1 >= 0) {
value1 = num1[end1--] - '0';
} else {
value1 = 0;
}
if (end2 >= 0) {
value2 = num2[end2--] - '0';
} else {
value2 = 0;
}
int valueRet = value1 + value2 + next;
if (valueRet > 9) {
next = 1;
valueRet -= 10;
} else {
next = 0;
}
addret += valueRet + '0';
}
if (next == 1) {
addret += '1';
}
reverse(addret.begin(), addret.end());
return addret;
}
};
addStrings
函数:
这个函数接受两个字符串 num1
和 num2
,这两个字符串表示要相加的非负整数。
函数会从字符串的末尾开始逐位相加,因为整数的低位在字符串的末尾。
end1
和 end2
分别初始化为两个输入字符串的末尾索引。
value1
和 value2
分别用于存储当前位置的两个字符所代表的数字。
next
用于存储进位,初始化为0。
addret
是一个空字符串,用于存储最终的相加结果。
进行循环迭代:
使用 while
循环,直到 end1
和 end2
都小于0,表示两个字符串的所有位都已相加完毕。
在循环中,首先获取 end1
和 end2
位置的字符,将其减去字符 '0' 得到对应的数字值。
然后将这两个数字值和进位 next
相加,得到 valueRet
。
如果 valueRet
大于9,表示需要进位,将 next
设置为1,并且 valueRet
减去10,确保结果不大于9。
将 valueRet
转换为字符,并将其添加到 addret
中,以构建相加的结果字符串。
继续下一位的相加。
处理最终进位:
循环结束后,如果最高位相加产生了进位,需要将额外的1添加到结果字符串的末尾。
最后,将 addret
字符串反转,以得到正确的顺序(因为之前是从末尾开始相加的)。
返回结果字符串 addret
,它包含了两个输入字符串相加的结果。
给定一个字符串
s
和一个整数k
,从字符串开头算起,每计数至2k
个字符,就反转这2k
字符中的前k
个字符。
如果剩余字符少于
k
个,则将剩余字符全部反转。如果剩余字符小于
2k
但大于或等于k
个,则反转前k
个字符,其余字符保持原样。示例 1:
输入:s = "abcdefg", k = 2 输出:"bacdfeg"
示例 2:
输入:s = "abcd", k = 2 输出:"bacd"
提示:
1 <= s.length <= 10(4)
s
仅由小写英文组成
1 <= k <= 10(4)
class Solution {
public:
void reverse(string& s, int begin, int k) {
int begin1 = begin;
int end1 = begin + k - 1;
while (begin1 < end1) {
swap(s[begin1], s[end1]);
begin1++;
end1--;
}
}
string reverseStr(string s, int k) {
int count = 0;
int begin = 0;
int end = 0;
while (end < s.size()) {
if (count == 2 * k) {
reverse(s, begin, k);
begin = end;
count = 0;
} else {
end++;
count++;
}
}
if (end - begin < k) {
reverse(s, begin, end - begin);
} else {
reverse(s, begin, k);
}
return s;
}
};
方法 void reverse(string& s, int begin, int k)
这个方法用于反转字符串s
中从begin
位置开始的k
个字符。
begin1
和end1
分别初始化为段的开始位置和结束位置(begin + k - 1
)。
通过一个while
循环,使用swap
函数交换begin1
和end1
位置上的字符,然后begin1
向后移动一位,end1
向前移动一位,直到begin1
大于等于end1
,完成反转操作。
方法 string reverseStr(string s, int k)
count
用于跟踪当前已经处理的字符数。
begin
和end-1
分别表示当前处理段的开始和结束位置。
通过一个while
循环遍历整个字符串:
如果count
达到2k
,说明当前段已经处理完毕,调用reverse
方法反转这段的前k
个字符,然后更新begin
为end
的位置,重置count
为0,以处理下一段。
否则,end
向后移动一位,count
加1,继续遍历。
循环结束后,根据end - begin
的值判断剩余字符的数量:
如果少于k
个,反转从begin
开始到字符串末尾的所有字符。
如果在k
到2k
个之间,只反转前k
个字符。
最后返回修改后的字符串s
。
给定一个字符串
s
,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。示例 1:
输入:s = "Let's take LeetCode contest" 输出:"s'teL ekat edoCteeL tsetnoc"
示例 2:
输入: s = "Mr Ding" 输出:"rM gniD"
提示:
1 <= s.length <= 5 * 10(4)
s
包含可打印的 ASCII 字符。
s
不包含任何开头或结尾空格。
s
里 至少 有一个词。
s
中的所有单词都用一个空格隔开。
class Solution {
public:
void reverse(string& s, int begin, int end) {
while (begin < end) {
swap(s[begin], s[end]);
begin++;
end--;
}
}
string reverseWords(string s) {
int begin = 0;
int end = 0;
while (begin < s.size()) {
int pos = s.find(' ', begin);
if (pos != std::string::npos) {
end = pos - 1;
} else {
end = s.size() - 1;
}
reverse(s, begin, end);
begin = end + 2;
}
return s;
}
};
方法 void reverse(string& s, int begin, int end)
这个辅助方法用于反转字符串s
中从begin
位置到end
位置的子字符串。
通过一个while
循环,当begin
小于end
时,使用swap
函数交换两个位置上的字符,然后begin
自增,end
自减,直到begin
大于或等于end
,完成子字符串的反转。
方法 string reverseWords(string s)
这个方法用于反转字符串s
中的每个单词。
初始化两个整数begin
和end
,分别表示当前处理的单词的开始和结束位置。
使用一个while
循环遍历整个字符串:
使用std::string::find
方法从当前begin
位置开始查找下一个空格的位置,这个位置标记了当前单词的结束。
如果找到了空格(pos
不等于std::string::npos
),则设置end
为pos - 1
,即当前单词最后一个字符的位置。
如果没有找到空格,说明已经到达字符串的末尾,此时设置end
为s.size() - 1
。
调用reverse
方法反转从begin
到end
的子字符串,即反转当前单词。
更新begin
为end + 2
,即下一个单词的开始位置。这里加2是因为end
是当前单词最后一个字符的位置,所以end + 1
是空格的位置,再加1才是下一个单词的开始位置。
循环继续直到begin
大于或等于字符串的大小,此时所有单词都已被反转。
函数最后返回修改后的字符串s
。
给定两个以字符串形式表示的非负整数
num1
和num2
,返回num1
和num2
的乘积,它们的乘积也表示为字符串形式。注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = "2", num2 = "3" 输出: "6"
示例 2:
输入: num1 = "123", num2 = "456" 输出: "56088"
提示:
1 <= num1.length, num2.length <= 200
num1
和num2
只能由数字组成。
num1
和num2
都不包含任何前导零,除了数字0本身。
num1="123",num2="456",num1*num2等价于123*456,等价于123*(400+50+6),等价于123*4*100+123*5*10+123*1*1。
class Solution {
public:
string multiply(string a, string b) {
//我们知道乘法问题其实就是加法问题
//这道题我们模拟一下过程就行
//我们用长的作为乘数,与被乘数的每一位相乘,需要写一个乘法函数
//我们需要用vector将每次乘的结果保存起来
//将vector中的每个串进行相应的移位操作,也就是后面补零即可
//写一个两两相加函数
//优化:滚动数组
//如果有一个为零,返回0即可
if(a == "0" || b == "0") return "0";
int m = a.size(), n = b.size();
if(m < n) {
return multiply(b, a);
}
//处理了之后我们默认a是长的,即乘数
vector vec(n, "");
for(int i = n - 1; i >= 0; i --) {
vec[i] = getMultiply(a, b[i]); //相乘
oper(vec[i], n - (i + 1)); //补零
}
string ans = "";
for(int i = 0; i < n; i ++) {
ans = add(ans, vec[i]);
}
return ans;
}
string getMultiply(string& a, char c) {
int x = c - '0';
string ans = "";
int carry = 0;
for(int i = a.size() - 1; i >= 0; i --) {
int sum = (a[i] - '0') * x + carry;
ans += sum % 10 + '0';
carry = sum / 10;
}
if(carry) ans += carry + '0';
reverse(ans.begin(), ans.end());
return ans;
}
void oper(string& a, int n) {
while(n --) {
a += '0';
}
}
string add(string& a, string& b) {
//逆序求和,跟当时链表高精度一样的思路
string ans = "";
// reverse(a);
// reverse(b);
int n = a.size() - 1, m = b.size() - 1;
int carry = 0;
// int idx = 0;
while(n >= 0 || m >= 0) {
int x = n < 0 ? 0 : a[n] - '0';
int y = m < 0 ? 0 : b[m] - '0';
int sum = x + y + carry;
ans += (sum % 10) + '0';
carry = sum / 10;
n --;
m --;
}
if(carry) ans += '1';
// reverse(ans);
reverse(ans.begin(), ans.end());
return ans;
}
};
边界情况处理
如果任一乘数为"0",则直接返回"0"。
确保乘数a
是较长的字符串
如果a
的长度小于b
的长度,则调换a
和b
,确保a
是较长的字符串。这样做是为了简化后续处理过程。
逐位乘法
使用vector
来存储每一步的乘法结果。这里n
是乘数b
的长度。
对于乘数b
中的每一位字符b[i]
,调用getMultiply(a, b[i])
计算它与a
的乘积,并将结果存储在vec[i]
中。
补零操作
对于每个乘积结果vec[i]
,调用oper(vec[i], n - (i + 1))
来补零,模拟乘法中的位移操作。
累加所有乘积结果
初始化一个空字符串ans
作为累加结果。
遍历vec
中的每个字符串,使用add(ans, vec[i])
将其累加到ans
中。
辅助函数
getMultiply(string& a, char c)
:计算字符串a
与单个字符c
的乘积,处理进位,并返回结果字符串。
oper(string& a, int n)
:在字符串a
的末尾补n
个零,模拟乘法的位移操作。
add(string& a, string& b)
:将两个字符串表示的数值相加,并返回结果字符串。这个函数从字符串的末尾开始逐位相加,处理进位。
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!