上一篇已经讲了string类的接口函数,然后根据查文档刷了牛客和力扣58最后一个单词的长度,
还有力扣415字符串相加,这篇继续跟着查文档来刷力扣题,体会C++刷题的方便。
目录
917. 仅仅反转字母 - 力扣(LeetCode)
代码解析:
387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
解析代码:
125. 验证回文串 - 力扣(LeetCode)
代码解析:
344. 反转字符串 - 力扣(LeetCode)
解析代码:
541. 反转字符串 II - 力扣(LeetCode)
解析代码:
557. 反转字符串中的单词 III - 力扣(LeetCode)
解析代码:
43. 字符串相乘 - 力扣(LeetCode)
解析代码:
本章完。
难度简单
给你一个字符串 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:
string reverseOnlyLetters(string s) {
}
};
这道题和快排的思路很类似,swap不知道有没有讲过在algorithm这个头文件里有,和我们在函数模板实现的差不多,这种常用的肯定能想起来了,像判断是不是字母等函数,想不起来可以自己写,想起来不清楚可以查文档:
class Solution {
public:
string reverseOnlyLetters(string s) {
int left = 0,right = s.size() - 1;
while(left < right)
{
while(left < right && !isalpha(s[left]))// 找字母,注意越界
{
++left;
}
while(left < right && !isalpha(s[right]))
{
--right;
}
swap(s[left++],s[right--]);// 交换后往中间走,传引用,
}
return s;
}
};
难度简单
给定一个字符串 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) {
}
};
可以暴力查找,是O(N^2),只有小写字母,可以用计数排序的思想:
class Solution {
public:
int firstUniqChar(string s) {
int countArr[26] = { 0 };
for (auto e : s)
{
countArr[e-'a']++;//相对映射到数组里++
}
for (int i = 0;i < s.size(); i++)
{
if (countArr[(s[i]-'a')] == 1)//从原字符串遍历字符的相对映射
{
return i;//第一个相对映射为1的就返回其下标
}
}
return -1;//没有出现一次的,输出-1
}
};
难度简单
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串 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 isPalindrome(string s) {
}
};
此题和快排思路类似,从两边找字符,判断是否相等,这题可能刚看会有其它思路,但把全部大写字母转成小写字母,或者反过来都是很方便的,动手动手:
class Solution {
public:
bool isPalindrome(string s) {
for(auto& e : s)
{
e = tolower(e);// 如果是大写就转小写,不是大写就不处理
}
int left = 0,right = s.size() - 1;
while(left < right )//找字母数字字符后比较
{
while(left < right && !isalpha(s[left]) && !isdigit(s[left]))
{
left++;
}
while(left < right && !isalpha(s[right]) && !isdigit(s[right]))
{
right--;
}
if(s[left] != s[right])
{
return false;
}
else
{
left++;
right--;
}
}
return true;
}
};
难度简单
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,
你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
提示:
1 <= s.length <= 10^5
s[i]
都是 ASCII 码表中的可打印字符
class Solution {
public:
void reverseString(vector& s) {
}
};
可以说我们以前都实现过了,就是这里变成了vector,
这里的vector就是一个存char类型的数组,我们收尾交换,进行翻转:
class Solution {
public:
void reverseString(vector& s) {
int left = 0,right = s.size() - 1;
while(left < right)
{
swap(s[left++],s[right--]);
}
}
};
难度简单
给定一个字符串 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:
string reverseStr(string s, int k) {
}
};
题目确实有点难懂,人话:每隔k个反转k个,末尾不够k个时全部反转。
一顿试错后的代码:
class Solution {
public:
void reverseString(string& s,int left,int right) {
while(left < right)
{
swap(s[left++],s[right--]);
}
}
string reverseStr(string s, int k) {
for(size_t i = 0; i < s.size(); i += 2*k)
{
if(i + k > s.size())
{
reverseString(s,i,s.size() - 1);
}
else
{
reverseString(s,i,i + k - 1);
}
}
return s;
}
};
还可以用官方库里面的左闭右开(上面实现的是左闭右闭)的reverse函数:
class Solution {
public:
void reverseString(string& s,int left,int right) {
while(left < right)
{
swap(s[left++],s[right--]);
}
}
string reverseStr(string s, int k) {
for(size_t i = 0; i < s.size(); i += 2*k)
{
if(i + k > s.size())
{
//reverseString(s,i,s.size() - 1);
reverse(&s[i],&s[s.size()]);
}
else
{
//reverseString(s,i,i + k - 1);
reverse(&s[i],&s[i + k]);
}
}
return s;
}
};
难度简单
给定一个字符串 s
,你需要反转字符串中每个单词的字符顺序,
同时仍保留空格和单词的初始顺序。
示例 1:
输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"
示例 2:
输入: s = "God Ding"
输出:"doG gniD"
提示:
1 <= s.length <= 5 * 10^4
s
包含可打印的 ASCII 字符。
s
不包含任何开头或结尾空格。
s
里 至少 有一个词。
s
中的所有单词都用一个空格隔开。
class Solution {
public:
string reverseWords(string s) {
}
};
(类似双指针的思想:)
class Solution {
public:
string reverseWords(string s) {
size_t left = 0,right = 0;
while(left < s.size())
{
while(right < s.size() && s[right] != ' ')// 找空格/结尾,要先判断结尾,防止越界访问
{
++right;
}
reverse(&s[left],&s[right]);// 注意是左闭右开(反正我是服了)
++right;//跳过空格,进行下一次判断
left = right;
}
return 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本身。
class Solution {
public:
string multiply(string num1, string num2) {
}
};
这题有点难就看题解了,这里用方法二:
class Solution {
public:
string multiply(string num1, string num2) {
int n = num1.size(), m = num2.size();
vector v(n + m, 0);//开n+m个0
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
int a = num1[n - i - 1] - '0';
int b = num2[m - j - 1] - '0';
v[i + j] += a * b;
}
}
for (int i = 0, carry = 0; i < v.size();++i)//carry进位
{
v[i] += carry;
carry = v[i] / 10;
v[i] %= 10;
}
string ret;
for (int i = v.size() - 1;i >= 0;--i)
{
if (ret.empty() && v[i] == 0)//如果ret是空的,并且v[i] == 0,就是前导0的情况
{
continue;
}
ret += (v[i] + '0');
}
return ret.empty() ? "0" : ret;//如果是空串就返回0,也可以在开头判断
}
};
下一篇:模拟实现string,深拷贝浅拷贝,拷贝构造和赋值重载的传统写法和现代写法。