文章目录
我们来看几道string相关的OJ,来练习一下string的使用。
题目链接: link
我们一起来看一下题:

我们来分析一下题目,这道题让我们干什么呢?
给我们一个字符串,该字符串中有英文字符也有非英文字符,要求我们去反转字符串中的所有英文字母,非英文字母的字符位置不动。
那是不是很简单啊,左右两个指针分别指向首尾,然后依次向中间移动寻找英文字母,找到后停下来,然后两个指针指向的英文字母进行交换,接着继续向中间移动,两者相遇结束。(是不是跟一趟快排的逻辑有点像啊)
class Solution {
public:
bool isletter(char x)
{
if((x>='a'&&x<='z')||(x>='A'&&x<='Z'))
return true;
return false;
}
string reverseOnlyLetters(string s) {
int begin=0;
int end=s.size()-1;
while(begin<end)
{
while((begin<end)&&!isletter(s[begin]))
begin++;
while((begin<end)&&!isletter(s[end]))
end--;
swap(s[begin],s[end]);
begin++;
end--;
}
return s;
}
};
代码呢也比较简单,相信大家都能看懂,就不过多解释了。
链接: link

题目让我们找出字符串中第一个不重复的字符,那我们最容易想到的就是暴力求解,从头到尾遍历字符串,依次拿每一个字符与其他字符进行比较,如果没有与之重复的则当前字符就是要找的字符,返回其下标,有重复的就不是,继续看下一个,最终一个也没找到就返回-1。
当然这样的时间复杂度就是O(N^2)
那有没有好一点的方法呢?
🆗,其实呢我们可以考虑用计数排序的思想去搞:
题目说了只包含小写字母
所以字符串中字符的范围就是【a,z】,那我们就可以创建一个大小为26的整型数组,然后用一个相对映射去统计每个字母的出现次数,a就映射到下标为0的位置,b就映射到下标为1的位置,依次类推。
那怎么让这些字母映射到对应的位置呢?
减去’a’得到的值是不是就是它们映射的位置啊,然后遍历字符串,每个字母映射的值是几,就让下标为几的元素++,初值全为0,这样遍历过后每个字母出现的次数就统计出来了。(下标0的元素的值就是a出现的次数,1位置就是b出现的次数…)
但是现在有一个问题,那就是出现一次的字母可能不止一个,我们怎么判断那个是第一个只出现一次的字母呢?
🆗,这里我们不要去遍历统计次数的数组,还是从前往后去遍历字符串,然后看哪个字母的次数是1,第一个是1的就是第一个只出现一次的字母。
class Solution {
public:
int firstUniqChar(string s) {
int count[26]={0};
for(auto e:s)
{
count[e-'a']++;
}
for(int i=0;i<s.size();i++)
{
if(count[s[i]-'a']==1)
return i;
}
return -1;
}
};
大家结合上面的分析再看一看代码,相信就能理解了。
接下来我们来看一道《剑指offer》于string相关的题目——替换空格

大家思考一下这道题可以怎么解?
是不是可以考虑用find+replace搞啊。
用find找的字符串中的所有空格,然后用replace将其替换成%20不就行了嘛。
我们来实现一下代码:
class Solution {
public:
string replaceSpace(string s) {
size_t pos=s.find(' ');
while(pos!=string::npos)//find找不到返回npos
{
s.replace(pos,1,"%20");
pos=s.find(' ');
}
return s;
}
};

🆗,就通过了。
那大家看一下,我们刚才上面那样写好吗,或者说有没有可以优化的地方?
是可以做一些优化的。
来看find是不是可以指定开始查找的位置啊,如果我们不传pos的话它默认是从起始位置开始查找的,但是这里我们要查找所有的空格,并且对它们进行替换,那第一个空格被替换之后,我们往后查找第二个的时候,还有必要从头开始找吗,是不是就可以从替换之后的尾部开始往后找啊,这样效率是不是就高了一点会。
所以我们可以这样改进一下:
那大家再想,还可以再优化吗?
其实还有一个地方可以做一些优化,大家想,我们这里replace是把空格替换成
%20,这样使用的空间是不是多了,那replace在替换的过程中是不是有可能空间不够进行扩容啊,那有没有什么办法可以避免replace的过程中可能会去频繁的扩容(扩容是有消耗的,特别是异地扩)。
🆗,我们是不是可以计算出需要多少空间,然后提前把空间开好啊。那大家说,这里应该用什么?
resize还是reserve,reserve可以改变容量帮我们开空间,而resize除了开空间还可以初始化,但是这里有必要对开好的空间进行初始化吗?
是不是没必要啊,所以我们用reserve就行了。
那需要多少空间呢,空格替换成%20,所以每个空格多两个空间,那我们可以统计一下空格数,然后提前把空间开好
写一下代码:
class Solution {
public:
string replaceSpace(string s) {
int count=0;
for(auto e:s)
{
if(e==' ')
count++;
}
s.reserve(s.size()+2*count);
size_t pos=s.find(' ');
while(pos!=string::npos)
{
s.replace(pos,1,"%20");
pos=s.find(' ',pos+3);
}
return s;
}
};

那除了上面那种方法,其实还可以考虑另一种思路:
我们可以创建一个新的string对象,然后遍历原串,不是空格,就直接+=到新串,是空格,就把
"%20"+=到新串。
这样的好处是不需要像上面那样挪动数据了,只不过多开了一点空间。
这个代码就非常简单:
class Solution {
public:
string replaceSpace(string s) {
string news;
for(auto e:s)
{
if(e!=' ')
news+=e;
else
news+="%20";
}
return news;
}
};

当然这种方法在+=的过程中也有可能会扩容,所以我们也可以把reserve那一步加上。
链接: link

输入一个字符串,求它的最后一个单词的长度。
那这是不是简单啊:
我们是不是可以用rfind去搞啊。
找到倒数第一个空格的位置pos是不是就能计算出长度了
用size - pos -1是不是就是最后一个单词长度。
注意:输入的字符串可能有空格,所以我们输入用getline。
写一下代码:
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin,s);
size_t pos=s.rfind(' ');
if(pos!=string::npos)
{
cout<<s.size()-pos-1<<endl;
}
}
🆗,提交一下:

有一个测试用例没过:
我们看到这个测试用例只有一个单词,所以找不到空格,但我们刚才没考虑找不到空格的情况。
那怎么解决?
🆗,这种情况答案不就是这一个单词的长度嘛,很好处理:
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin,s);
size_t pos=s.rfind(' ');
if(pos!=string::npos)
{
cout<<s.size()-pos-1<<endl;
}
else
{
cout<<s.size()<<endl;
}
}

链接: link

我们来一起看一下:
这道题是给定两个字符串形式的非负整数 num1 和num2 ,让我们计算它们的和并同样以字符串形式返回。
我们来分析一下应该怎么做?
就拿这个例子来说:
这里我们是不是应该倒着走啊,从低位开始加,首先取到两个字符串的最后一个字符,相加,7+6是13,但是我们这里把3保存下来,1是不是要进到上一位啊,所以我们应该搞一个变量来保存进位;
那然后再去加它们对应的倒数第二位,依次往前走,所以这应该是一个循环的过程,那什么时候结束?
是不是两个字符串全都遍历完才结束啊,当然它们可能会有一个先走完,那另一个剩下的每次跟0相加就行了。
所以我们应该先获取一下它们最后一个元素的下标end,加一个数,两者的end就- -一次,减到-1就是遍历完了。
然后里面我就去循环走我们的这个逻辑。
那我们来写一下代码:
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1;
int end2=num2.size()-1;
while(end1>=0||end2>=0)
{
}
}
};
🆗,那在循环里面我们就依次去取对应的两个字符进行相加了。
但是这里我们能直接用字符相加吗?我们的字符取出来是啥,是不是取的是它们对应的ASCII码值啊,想拿到它对应的数字,怎么办?
是不是应该减去'0'啊
int val1=num1[end1]-'0';
但是呢,这里还存在一个问题:我们这里是不是只要有一个字符串没走完循环就不结束啊,也就是即使在循环里面,也有可能有一个已经走完了,所以我们这里直接取这个end是不是可以越界啊,所以加个判断:
当然这个地方我们可以用三目运算符来简化一下:
然后就该相加了,但是相加是不是会产生进位啊,所以我们再定义一个变量表示进位,初值给个0。
那相加之后,如果和大于等于10,进位的值是不是就该变成1 了。当然如果小于10 那就还是0。
所以我们可以这样写:
next=sum/10;
那另外如果和大于10,我们是不是只留下各位的数就行了。
sum%=10;
然后呢,得出的结果我们是不是要存下来。
题目要求最后还是返回一个字符串,所以我们再创建一个string对象保存结果。
但是现在面临一个问题,我们先得到的是不是低位的数字啊,它们应该放在后面,所以这里我们每次保存得出的结果应该是头插到string对象中,那我们就可以用insert,每次插入到下标0的位置。
注意这里插入的时候要把字符0再加上。
那加完之后它们的end的位置是不是都要- -一下啊。
那这样循环结束,是不是就得到结果了。
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1;
int end2=num2.size()-1;
int next=0;//进位
string ret;
while(end1>=0||end2>=0)
{
int val1=(end1>=0?num1[end1]-'0':0);
int val2=(end2>=0?num2[end2]-'0':0);
int sum=val1+val2+next;
next=sum/10;
sum%=10;
ret.insert(0,1,sum+'0');
end1--;
end2--;
}
return ret;
}
};
我们来提交一下:
🆗,有一些测试用例没过。我们来看一下:
看当前报错给的这个用例,1和9我们输出的是0,什么问题啊?
是不是循环结束之前最后一次得出的进位如果是0那就不用管了,但如果是1 ,我们是不是还得加上去啊。
🆗,我们刚才是不是忽略掉这个情况了:
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1;
int end2=num2.size()-1;
int next=0;//进位
string ret;
while(end1>=0||end2>=0)
{
int val1=(end1>=0?num1[end1]-'0':0);
int val2=(end2>=0?num2[end2]-'0':0);
int sum=val1+val2+next;
next=sum/10;
sum%=10;
ret.insert(0,1,sum+'0');
end1--;
end2--;
}
if(next==1)
ret.insert(0,1,'1');
return ret;
}
};

🆗,这下就通过了。
但是大家看一下,我们刚才的这种搞法效率是不是比较低啊,我们这里每次都要调用insert头插挪动数据,那是不是O(N^2)啊。
我们上一篇文章也提到了,insert是不是能少用就少用啊。这里效率低主要就低在insert这里了。
所以,能不能想办法改进一下啊。
那我们可以怎么改进一下呢?
🆗,insert头插需要挪动数据效率低,那我们就不用头插了呗,我们就依次放到后面,一个个尾插,最后我们再逆置一下不就行了嘛。
那逆置呢,我们可以自己写一个函数。
但是,其实不需要。因为C++的算法库里其实给我们提供了逆置的函数,我们可以直接用:
我们看到这里使用的时候去传迭代器区间就行了。
修改成这样。
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1;
int end2=num2.size()-1;
int next=0;//进位
string ret;
while(end1>=0||end2>=0)
{
int val1=(end1>=0?num1[end1]-'0':0);
int val2=(end2>=0?num2[end2]-'0':0);
int sum=val1+val2+next;
next=sum/10;
sum%=10;
//ret.insert(0,1,sum+'0');
ret+=(sum+'0');
end1--;
end2--;
}
if(next==1)
//ret.insert(0,1,'1');
ret+='1';
reverse(ret.begin(),ret.end());
return ret;
}
};

效率明显就提升了。
🆗,那还有没有可以优化的地方?
这里涉及到插入数据,我们就可以考虑干嘛?
是不是可以提前把空间开好以此来避免在插入数据的时候可能引发扩容。
那大家思考一下对于这道题我们应该提前开多少空间合适?
大家想,两个数相加,结果最多是不是会比长的那个数的位数多出一位啊。
比如,两个最大的两位数相加,99+99,也就3位嘛。
所以:
就可以这样搞一下。
class Solution {
public:
string addStrings(string num1, string num2) {
int end1=num1.size()-1;
int end2=num2.size()-1;
int next=0;//进位
string ret;
ret.reserve(num1.size()>num2.size()?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 sum=val1+val2+next;
next=sum/10;
sum%=10;
//ret.insert(0,1,sum+'0');
ret+=(sum+'0');
end1--;
end2--;
}
if(next==1)
//ret.insert(0,1,'1');
ret+='1';
reverse(ret.begin(),ret.end());
return ret;
}
};

🆗,这篇文章就到这里,欢迎大家指正!!!

1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析: 在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1: print(k)k=k/2A.1000 B.10C.11D.9解析: 按照题意每次循环K/2,直到K值小于等
我在第三个练习中停留在第四个RailsforZombies实验室。这是我的任务:创建将创建新僵尸的操作,然后重定向到创建的僵尸的显示页面。我有以下参数数组:params={:zombie=>{:name=>"Greg",:graveyard=>"TBA"}}我写了下面的代码作为解决方案:defcreate@zombie=Zombie.create@zombie.name=params[:zombie[:name]]@zombie.graveyard=params[:zombie[:graveyard]]@zombie.saveredirect_to(create_zombie_path
我试图解决在线书籍eloquentjavascript2ndedition的递归练习:问题是这样的:We’veseenthat%(theremainderoperator)canbeusedtotestwhetheranumberisevenoroddbyusing%2tocheckifit’sdivisiblebytwo.Here’sanotherwaytodefinewhethera(positive,whole)numberisevenorodd:Zeroiseven.Oneisodd.ForanyothernumberN,itsevennessisthesameasN-2.De
我刚拿到DouglasCrockford的Javascript:TheGoodParts,我在理解他关于原型(prototype)的示例之一时遇到了一些困难。书中代码如下:if(typeofObject.create!=="function"){Object.create=function(o){varF=function(){}F.prototype=o;returnnewF;};}我假设此代码用于定位函数的原型(prototype)。但为什么要使用如此复杂的方法呢?为什么不直接使用variable.prototype?Crockford是Javascript方面的领先专家,因此我确
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭11年前。我目前有Notepad++和AptanaStudio。是否有任何其他开发环境可以简化javascript代码的编写?谢谢。
反转二维数组的值,可以扩展n次。[1,[2,[3,...[n,null]]]]给定:所有数组的长度始终为2列表中的最后一个数组将包含一个null索引1示例:[1,[2,[3,null]]]将输出[3,[2,[1,null]]][1,[2,[3,[4,null]]]]会输出[4,[3,[2,[1,null]]]]我不确定我描述的是否正确,但我今天遇到了这个练习并想出了一个相当明显的解决方案。varars=[1,[2,[3,null]]],rev=null;functionr(x){rev=(rev==null)?[x[0]]:[x[0],rev];if(x[1]!==null)r(x[1
综合练习一题目要求:实验范图实现PC机之间互通配置思路:配置过程:配置终端设备及3700交换机实现此案例需要按照如下步骤进行。1)配置PC的IP地址和网关2)配置SW1/5/6的vlan为10/20/30,交换机之间的链路为Trunk,与PC间为Access3)配置SW2/3/7的vlan为40/50,交换机之间的链路为Trunk,与PC间为Access4)配置SW4/8/9的vlan为60/70/80,交换机之间的链路为Trunk,与PC间为Access5)配置R1/R2/R3的接口IP地址6)配置每个VLAN的网关接口IP地址SW1为vlan10/20/30的网关设备:interfacev
1.要求:1.根据提示,在指定位置写出编译版本,要求使用^符号,版本要求在0.6.0及以上。2.根据提示,在指定位置写出所定义的合约名称。3.为了查看程序的效果,我们使用在线Solidity开发工具RemixIDE编译和运行Solidity程序。中文在线版:在浏览器打开下方链接: Remix-中文版-智谷星图。第1步–在文件浏览器选项卡下,新建一个Firstapp.sol文件,把我们补充完整的代码直接复制过来。第2步–在SOLIDITY编译器选项卡下,选择0.6.5的那个编译器版本并单击 编译Firstapp.sol 按钮,开始编译。编译成功后会根据本地客户端和版本内容弹出提示,可以不用处理。
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion我目前正在教员工ECMA脚本,因为维护我们使用的工作流系统需要它,我需要一些挑战作为练习。我们已经涵盖了大部分语言,他现在非常熟悉语法,所以我只需要他开始使用它。我需要给他提供练习,让他进行逻辑思考。例如,他了解什么是if和switch
目录目标一、元素定位目标1. 如何进行元素定位?2. 浏览器开发者工具2.1 如何使用浏览器开发者工具3. 元素定位方式3.1 id 定位3.2 name 定位3.3 class_name 定位3.4 tag_name 定位3.5 link_text 定位3.6 partial_link_text 定位4. 定位一组元素 4.1 find_elements_by_xxx()4.2 案例4.3 示例代码二、XPath、CSS 定位目标为什么要学习XPath、CSS 定位?1. 什么是XPath?2. XPath 定位策略(方式)2.1 路径定位(绝对路径、相对路径)2.2 利用元素属性2.3 属