目录
反转字母
学习了string后,这道题用c++就会变得很容易解决。
我们可以利用双指针的方式遍历string
记录首尾指针
size_t begin = 0,end = s.size()-1;
外循环,保证begin<end
while(begin<end)
{ }
然后进入内部后,分别有两个循环,begin和end分别向中间遍历,根据题目要求,交换字母,非字母不管,与使我们得写个判断是否为有效字母的函数,在遍历过程中,发生了位置的相对变化,所以仍然需要判断begin是否小于end。
完善代码:
bool isValid(char ch)
{
if(ch>='a'&&ch<='z')
{
return true;
}
if(ch>='A'&&ch<='Z')
{
return true;
}
return false;
}
while(begin<end && !isValid(s[begin]))
{
++begin;
}
while(begin<end && !isValid(s[end]))
{
--end;
}
接下来进行交换两个字母,用到类交换模板swap函数(不是string::swap)注意完成交换后需要更新begin和end的值
下面是完整代码:
class Solution {
public:
bool isValid(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 && !isValid(s[begin]))
{
++begin;
}
while(begin<end && !isValid(s[end]))
{
--end;
}
swap(s[begin],s[end]);
++begin;
--end;
}
return s;
}
};
唯一字符
索引:数组下标
这里题目的s只有26个小写字母,所以无需判断合法
这里我们用哈希思想建立26个字母的映射关系
int count[26] = {0};
for(auto ch : s)
{
count[ch - 'a']++;
}
接着我们只需返回对应的数组下标就可以啦
完整代码:
class Solution {
public:
int firstUniqChar(string s) {
int count[26] = {0};
for(auto ch : s)
{
count[ch - 'a']++;
}
for(int i=0;i<s.size();i++)
{
if( count[s[i] - 'a'] == 1)
return i;
}
return -1;
}
};
最后一个单词
因为字符串末尾不以空格结尾, 我们可以用rfind来查找最后一个空格,利用rfind找不到返回npos作为判断条件
#include <iostream>
using namespace std;
#include<string>
int main() {
string s;
cin >> s;
size_t pos = s.rfind(' ');
if(pos != string::npos)
{
cout<<s.size()-pos-1<<endl;
}
else
cout<<s.size()<<endl;
}
注意这里输出单词要去掉空格,也就是-1。
记住,两个下标相减,得到的长度是一个左闭右开的区间。
但这段代码是有问题的,我们都知道scanf遇到空格或\n会停止,cin也是如此,为了避免这一问题,我们可以使用c++的getline函数,这样就可以将string以整行的方式输出了。
第一个可以自定义结束标志,换行为通用结束标志
getline(cin,s);
字符串相加
注意这里的限制条件,明确告诉我们不能用整数及相应的库的形式,我们可以像小学计算两个数个位十位百位分别相加,满则进1。
从后往前加,判断条件是两个数都达到最高位停止
string addStrings(string num1, string num2) {
int end1 = num1.size()-1,end2 = num2.size()-1;
string str;
while(end1>=0 || end2>=0)
{}
注意这里用或表示结束条件
利用ascii码的顺序性,可以将起始位置设成 '0',相减就能得到进行相加的值,因为要多次循环,所以要判断下表位置是否加到了0位
int val1 = end1 >= 0 ? num1[end1]-'0':0;
int val2 = end2 >= 0 ? num2[end2]-'0':0;
int ret = val1 + val2;
因为涉及进位,我们在内外定义一个next变量控制进位,ret也要加上next
这里我们可以用0,1来控制next:
if(ret>9)
{
next = 1;
ret = ret%10;
}
else
{
next = 0;
}
用else将next置0是为了第二次不满足进位条件时不能还是加1
第二种方法:
next = ret / 10;
插入数据并推动循环:
str.insert(0,1,ret+'0');//首插
//str.insert(str.begin(),ret+'0');
--end1;
--end2;
注意如果两个位数一样的在最后一次循环后发生进位是无法被计算的,这里我们在循环外判断这种情况
if(next == 1)
{
str.insert(0,1,'1');
}
代码能够正常运行,但存在效率问题,头插的n^2消耗还是挺大的,所以我们可以采用尾插+reverse的组合优化。如果遇到过大的数据需要进行扩容,我们这里提前开好空间是不是也能减少消耗呢?(可以选择以最大位为标准)
完整代码:
class Solution {
public:
string addStrings(string num1, string num2) {
int end1 = num1.size()-1,end2 = num2.size()-1;
int next=0;
string str;
str.reserve(num1.size()>num2.size() ? num1.size()+1:num2.size()+1);
//str.reserve(end1>end2 ? num1.size()+1:num2.size()+1);
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;
//str.insert(0,1,ret+'0');//首插
//str.insert(str.begin(),ret+'0');
str += ret+'0';
--end1;
--end2;
}
if(next == 1)
{
// str.insert(0,1,'1');
str+='1';
}
reverse(str.begin(),str.end());
return str;
}
};