题目描述
「句子」是一个用空格分隔单词的字符串。给你一个满足下述格式的句子 text :
句子的首字母大写
text 中的每个单词都用单个空格分隔。
请你重新排列 text 中的单词,使所有单词按其长度的升序排列。如果两个单词的长度相同,则保留其在原句子中的相对顺序。
请同样按上述格式返回新的句子。
示例 1:
输入:text = "Leetcode is cool"
输出:"Is cool leetcode"
解释:句子中共有 3 个单词,长度为 8 的 "Leetcode" ,长度为 2 的 "is" 以及长度为 4 的 "cool" 。
输出需要按单词的长度升序排列,新句子中的第一个单词首字母需要大写。
示例 2:
输入:text = "Keep calm and code on"
输出:"On and keep calm code"
解释:输出的排序情况如下:
"On" 2 个字母。
"and" 3 个字母。
"keep" 4 个字母,因为存在长度相同的其他单词,所以它们之间需要保留在原句子中的相对顺序。
"calm" 4 个字母。
"code" 4 个字母。
示例 3:
输入:text = "To be or not to be"
输出:"To be or to be not"
题目分析
这道题目是力扣上的一道原题,看似不复杂,(难度为中等),但其实里面有许多细节是需要注意的。就比如说它的要求,要排完之后首字母大写,按照单词长度升序排列,而且原先单词长度相等的,排完之后相对位置不能改变。针对这道题,我足足花了将近两个小时才把要求的功能完全实现,在VS上是可以的,但是在力扣上就超时了,很难受,主要还是我用了冒泡的缘故。以下是我的思路,当做反面典型吧。
(1)首先创建一个vector容器,把句子划分为单词,装到容器中,这里要注意,装的过程中,顺便给每一个单词后缀都加一个空格" ",以便于之后重建句子。
(2)之后对于容器中的单词,用了最简单的冒泡排序把单词长度由小到大排了一下,(这就是超时的原因);
(3)再用一个堆栈把容器中的单词依次压栈;
(4)最后用一个字符串去接受栈中的单词。
总体来说,代码整体过于繁杂,而且冒泡排序绝对不会用在这种算法题中的,是我太天真了,以为不会超时!!!
class Solution {
public:
string arrangeWords(string& text) {
//把text分开加入v中
vector<string> v;
string v_sub;
for (int i = 0; i < text.size(); i++)
{
if (text[i] != ' ')
{
if (text[i] < 97)
{
text[i] += 32;
}
v_sub += text[i];
if (i == text.size() - 1)
{
v_sub += " ";
v.push_back(v_sub);
}
}
else
{
v_sub += " ";
v.push_back(v_sub);
v_sub = "";
}
}
string return_string;
stack<string> sta;
int return_string_sz = v.size() - 1;
for (int m = 0; m < v.size(); m++)
{
for (int n = 0; n < v.size() - m-1; n++)
{
if (v[n].size() > v[n + 1].size())
{
string temp;
temp = v[n];
v[n] = v[n + 1];
v[n + 1] = temp;
}
}
sta.push(v[return_string_sz--]);
}
int sta_sz = sta.size();
for (int i = 0; i < sta_sz; i++)
{
return_string += sta.top();
sta.pop();
}
return_string[0] -= 32;
return_string.pop_back();
return return_string;
}
};
下面言归正传,还是来看一看大佬怎么做的吧,以下代码摘自力扣大佬题解。
//stable_sort: 132ms -> 76ms
class Solution {
public:
string arrangeWords(string text) {
int index = 0, t_len = text.size();
text[0] -= ('A' - 'a');
vector<pair<int,int>> res;
for(int i = 0; i <= t_len; i++) {
if(i == t_len || text[i] == ' ') {
//res.push_back(make_pair(index, i - index));
res.emplace_back(index, i - index);
index = i + 1;
}
}
//之前使用的sort,主要是不知道有stable_sort这一说
stable_sort(res.begin(), res.end(), [](const auto& a, const auto& b) {
return a.second < b.second;
});
string ans;
ans.reserve(t_len + 1);
for(const pair<int,int>& p: res) {
//ans += text.substr(p.first, p.second) + " ";
ans.append(text, p.first, p.second).push_back(' ');
}
ans[0] += ('A' - 'a');
ans.pop_back();
return ans;
}
};
看了这段代码,只能感叹妙不可言。
它用容器res去维护了一组包含两个整数的pair<int,int>,其中第一个int表示单词在句子中的起始索引,第二个表示单词的长度。
这里面用到了容器的emplace_back()方法。
这样以来,就得到了装有很多pair的容器,里面每个pair都存储了单词的起始索引和长度,这个时候再按照长度进行排序就OK了,所以对sort进行重载,实现对pair里面的second进行排序。
stable_sort(res.begin(), res.end(), [](const auto& a, const auto& b) {
return a.second < b.second;
});
这里使用到了lambda函数(学以致用)。
最后,再用一个空的字符串依次去接收,这里用到了append(),里面有三个参数,这里第一个代表源字符串,第二个为起始位置,第三个为长度,起始就是往一个字符串里面去添加一个字符串,只不过是你可以指定长度、起始位置。
最后是运行结果
输入 “Keep calm and code on”
输出:"On and keep calm code"
没毛病,老铁。