解题思路
- 先将句子中所有的字符串取出放入字符串数组中。
- 再对数组中的字符串进行操作后重新连接
遍历句子取字符串的思路:将遇到的字符放进临时字符串中,遇得空格或者标点符号,就将临时字符串放进字符串数组中,并且将临时字符串清空。
模板代码
一、字符串前后有空格
s +=" ";//在字符串最后位置加上空格,这样最后一个字符串就不会遗漏
string temp = "";//创建临时字符串
vector<string> res;//存放字符串数组
int main()
{
for (char ch : s)//遍历字符串
{
if (ch == ' ')//遇见空格或者这里也可以根据题目要求,将空格改标点符号
{
//遇见空格,代表字符串s中的一个单词已经全部存储在临时字符串中
if (!temp.empty())//临时字符串非空
{
//将临时字符串存储在字符串数组中
res.push_back(temp);
temp.clear();//将临时字符串清空,方便存入字符串s中下一个单词
}
}
else//临时字符串是空,代表已经遍历到字符串最后一个位置了。
{
temp += ch;
}
}
}
二、字符串前后没有空格
s += " ";
string temp = "";
vector<string> res;
for (char ch : s)
{
if (ch == ' ')
{
res.push_back(temp);
temp.clear();
}
else
{
temp += ch;
}
}
有关字符串的题目
最后一个单词的长度
反转字符串中的单词
反转单词顺序
截断句子
字符串中不同整数的数目
最常见的单词
山羊拉丁文
检查单词是否为句子中其他单词的前缀
重新排列单词间的空格
将句子排序
解题方法:
最后一个单词的长度
题目描述:给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
从题目描述中我们可以看出,该题目可以直接套用模板1,返回字符串数组尾的元素长度。
class Solution {
public:
int lengthOfLastWord(string s) {
s+=' ';
string temp;
vector<string> res;
for(char ch:s)
{
if(ch==' ')
{
if(!temp.empty())
{
res.push_back(temp);
temp.clear();
}
}
else
{
temp+=ch;
}
}
if(res.empty())return 0;
return res.back().size();
}
};
反转字符串中的单词
题目描述:给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
我们根据题目要求可以判断出,我们只需要将字符串中所有单词的字母顺序颠倒即可。
class Solution {
public:
string reverseWords(string s) {
s+=' ';
string temp="";
vector<string>res;
for(char ch:s)
{
if(ch==' ')
{
res.push_back(temp);
temp.clear();
}
else
{
temp+=ch;
}
}
s.clear();//将原字符串清空
for(auto&str:res)
{
reverse(str.begin(),str.end());
s+=str+' ';//将单词用' '空格隔开
}
//执行在这里,意味着将所有单词全部反转,但是最后一个单词多了一个空格
s.pop_back();//将最后一个空格删除
return s;
}
反转单词顺序
题目描述:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
class Solution {
public:
string reverseWords(string s) {
if(s.empty())return "";
s+=" ";
string temp="";
vector<string>res;
for(char ch:s)
{
if(ch==' ')
{
if(!temp.empty())
{
res.push_back(temp);
temp.clear();
}
}
else
{
temp+=ch;
}
}
s.clear();
reverse(res.begin(),res.end());
for(auto&str:res)
{
s+=str+' ';
}
s.pop_back();
return s;
}
};
截断句子
题目描述:句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)给你一个句子 s 和一个整数 k ,请你将 s 截断 ,使截断后的句子仅含 前 k 个单词。返回 截断 s 后得到的句子。
输入:s = “Hello how are you Contestant”, k = 4
输出:“Hello how are you”
解释:
s 中的单词为 [“Hello”, “how” “are”, “you”, “Contestant”]
前 4 个单词为 [“Hello”, “how”, “are”, “you”]
因此,应当返回 “Hello how are you”
示例中没有前置或者后置空格,所以用模板二。
class Solution {
public:
string truncateSentence(string s, int k) {
s+=" ";
string temp="";
vector<string>res;
for(char ch:s)
{
if(ch==' ')
{
res.push_back(temp);
temp.clear();
}
else
{
temp+=ch;
}
}
s.clear();
for(int i=0;i<k;++i)
{
s+=res[i]+' ';
}
s.pop_back();
return s;
}
};
字符串中不同整数的数目
题目描述:给你一个字符串 word ,该字符串由数字和小写英文字母组成。
请你用空格替换每个不是数字的字符。例如,“a123bc34d8ef34” 将会变成 " 123 34 8 34" 。注意,剩下的这些整数为(相邻彼此至少有一个空格隔开):“123”、“34”、“8” 和 “34” 。
返回对 word 完成替换后形成的 不同 整数的数目。
只有当两个整数的 不含前导零 的十进制表示不同, 才认为这两个整数也不同。
示例 1:
输入:word = “a123bc34d8ef34”
输出:3
解释:不同的整数有 “123”、“34” 和 “8” 。注意,“34” 只计数一次。
输入:word = “a1b01c001”
输出:1
解释:“1”、“01” 和 “001” 视为同一个整数的十进制表示,因为在比较十进制值时会忽略前导零的存在。
class Solution {
public:
int numDifferentIntegers(string word) {
set<string>s;//用set可进行去重
string temp="";
word+='a';//在字符串末尾加上一个字母,保证在遍历的时候如果有整数就不会遗漏
for(char ch:word)
{
if(isalpha(ch))//如果是字母
{
if(!temp.empty())//临时字符串为空
{
s.insert(temp);
temp.clear();
}
}
else
{
if(temp=="0")temp.clear();//整数前面有0:如012就是12,将0清除
temp+=ch;
}
}
return s.size();
}
};
最常见的单词
**题目描述:**给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多,同时不在禁用列表中的单词。
题目保证至少有一个词不在禁用列表中,而且答案唯一。
禁用列表中的单词用小写字母表示,不含标点符号。段落中的单词不区分大小写。答案都是小写字母。
示例:
输入:
paragraph = “Bob hit a ball, the hit BALL flew far after it was hit.”
banned = [“hit”]
输出: “ball”
解释:
“hit” 出现了3次,但它是一个禁用的单词。
“ball” 出现了2次 (同时没有其他单词出现2次),所以它是段落里出现次数最多的,且不在禁用列表中的单词。
注意,所有这些单词在段落里不区分大小写,标点符号需要忽略(即使是紧挨着单词也忽略, 比如 “ball,”),
"hit"不是最终的答案,虽然它出现次数更多,但它在禁用单词列表中。
class Solution {
public:
string mostCommonWord(string paragraph, vector<string>& banned) {
paragraph+=" ";
string temp="";
map<string,int>m;//哈希表记录单词出现频次
set<string>ban(banned.begin(),banned.end());//把禁用列表放到集合中方便查找
for(char ch:paragraph)
{
if(!isalpha(ch))//将字符串中所有的单词分割出来
{
if(!temp.empty())
{
m[temp]++;
temp.clear();
}
}
else
{
temp+=tolower(ch);//将所有字母转换为小写字母
}
}
vector<string>words;
for(auto p:m)
{
words.push_back(p.first);
}
sort(words.begin(), words.end(), [&](string &s, string &p) { return m[s] > m[p]; });
if(banned.empty())//如果没有禁用单词,直接返回排序后列表的首元素
{
return words[0];
}
for(auto w:words)//遍历列表,除了禁用单词外,第一个单词就是常见单词
{
if(ban.find(w)==ban.end())
{
return w;
}
}
return "";
}
};
山羊拉丁文
给定一个由空格分割单词的句子 S。每个单词只包含大写或小写字母。
我们要将句子转换为 “Goat Latin”(一种类似于 猪拉丁文 - Pig Latin 的虚构语言)。
山羊拉丁文的规则如下:
如果单词以元音开头(a, e, i, o, u),在单词后添加"ma"。
例如,单词"apple"变为"applema"。
如果单词以辅音字母开头(即非元音字母),移除第一个字符并将它放到末尾,之后再添加"ma"。
例如,单词"goat"变为"oatgma"。
根据单词在句子中的索引,在单词最后添加与索引相同数量的字母’a’,索引从1开始。
例如,在第一个单词后添加"a",在第二个单词后添加"aa",以此类推。
返回将 S 转换为山羊拉丁文后的句子。
示例 1:
输入: “I speak Goat Latin”
输出: “Imaa peaksmaaa oatGmaaaa atinLmaaaaa”
class Solution {
public:
string toGoatLatin(string sentence) {
sentence+=" ";
vector<string>res;
string temp="";
string vowels="aeiouAEIOU";
for(char ch:sentence)
{
if(ch==' ')
{
res.push_back(temp);
temp.clear();
}
else
{
temp+=ch;
}
}
sentence.clear();
for(int i=0;i<res.size();++i)
{
//字符串中单词的首元素为元音字母
if(vowels.find(res[i][0])!=-1)
{
sentence+=res[i];
}
else
{
//如果不是,那么就将单词的首元素字母增加在原单词中,然后将首字母删除
string t=res[i]+res[i][0];
t.erase(t.begin());
sentence+=t;
}
sentence+="ma";
sentence.insert(sentence.size(),i+1,'a');
sentence+=' ';
}
sentence.pop_back();
return sentence;
}
};
检查单词是否为句子中其他单词的前缀
给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。
如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。如果 searchWord 不是任何单词的前缀,则返回 -1 。
字符串 s 的 前缀 是 s 的任何前导连续子字符串。
示例 1:
输入:sentence = “i love eating burger”, searchWord = “burg”
输出:4
解释:“burg” 是 “burger” 的前缀,而 “burger” 是句子中第 4 个单词。
class Solution {
public:
int isPrefixOfWord(string sentence, string searchWord) {
sentence+=" ";
string temp="";
vector<string>res;
for(char ch:sentence)
{
if(ch==' ')
{
res.push_back(temp);
temp.clear();
}
else
{
temp+=ch;
}
}
for(int i=0;i<res.size();++i)
{
if(res[i].find(searchWord)==0) return i+1;
}
return -1;
}
};
重新排列单词间的空格
给你一个字符串 text ,该字符串由若干被空格包围的单词组成。每个单词由一个或者多个小写英文字母组成,并且两个单词之间至少存在一个空格。题目测试用例保证 text 至少包含一个单词 。
请你重新排列空格,使每对相邻单词之间的空格数目都 相等 ,并尽可能 最大化 该数目。如果不能重新平均分配所有空格,请 将多余的空格放置在字符串末尾 ,这也意味着返回的字符串应当与原 text 字符串的长度相等。
返回 重新排列空格后的字符串 。
用模板一
class Solution {
public:
string reorderSpaces(string text) {
text+=" ";
string temp="";
vector<string>res;
int cnt=-1;//因为代码最开始给字符串增加了一个空格
for(char ch:text)
{
if(ch==' ')
{
cnt++;
if(!temp.empty())
{
res.push_back(temp);
temp.clear();
}
}
else
{
temp+=ch;
}
}
text.clear();
int n=res.size();
if(n==1)
{
text+=res[0];
text.insert(text.size(),cnt,' ');
return text;
}
int bank=cnt/(n-1);
int remain=cnt-bank*(n-1);
for(int i=0;i<n-1;++i)
{
text+=res[i];
text.insert(text.size(),bank,' ');
}
text+=res.back();
if(remain>0)text.insert(text.size(),remain,' ');
return text;
}
};
class Solution {
public:
string sortSentence(string s) {
s += " ";
string temp = "";
vector<string> res;
for (char ch : s)
{
if (ch == ' ')
{
res.push_back(temp);
temp.clear();
}
else
temp += ch;
}
s.clear();
sort(res.begin(),res.end(),[&](string&a,string&b){return a.back()<b.back();});
for(auto&str:res)
{
str.pop_back();//将单词中的数字清除
s+=str+' ';
}
s.pop_back();
return s;
}
};