Leetcode刷题总结(2):字符串问题
38
题意
这道题的题面很有趣:生成一个这样的序列:
1:"1"
2:"11"(1个1)
3:"21"(2个1)
4:"1211"(1个2,1个1)
5:"111221"(1个1,1个2,2个1)
给出n,求第n个序列长什么样子。
分析
不妨来多计算几个数:
6:"312211"
7:"13112221"
8:"1113213211"
感觉序列长度大致是线性增长的。那就直接暴力好了。
查看了一下题解。感觉这种东西很难有通项公式。这个序列是Conway的“Look-and-say”序列(https://en.wikipedia.org/wiki/Look-and-say_sequence),在https://leetcode.com/problems/count-and-say/discuss/16113/How-to-proof-the-COUNT-is-always-less-than-10上有更多说明,比如不会出现超过3的数字。数列长度的增长速率大约是30%。
代码
class Solution {
public:
string countAndSay(int n) {
if (n == 1)
return "1";
vector<int> a(1, 1);
vector<int> b;
for (int i = 1; i < n; i++) {
int j = 1, cnt = 1;
while (j < a.size()) {
if (a[j] != a[j-1]) {
b.push_back(cnt); // cnt个
b.push_back(a[j-1]); // a[j-1]
cnt = 1;
}
else {
cnt++;
}
j++;
}
if (cnt != 0) {
b.push_back(cnt);
b.push_back(a[a.size()-1]);
}
a = b;
b.clear();
}
string ans;
for (int i = 0; i < a.size(); i++)
ans += '0' + a[i];
return ans;
}
};
时间为90.54%。惊了,纯暴力这么强的么(当然也是因为推递归公式很难)。
71
题意
题意倒是非常简单。给你一个Unix样式的路径,让你简化。
分析
最初的想法很简单。不妨假定路径是合法的,则只有3种情况:
- 普通的路径
-
.
:相当于没有 -
..
:相当于上移一层
那就搞一个栈好了。
在调试过程中遇到的比较不好想到的Corner case是"/.."
。看起来不合法,但实际上是合法的。
代码
class Solution {
public:
string simplifyPath(string path) {
stack<string> s;
string dir = "";
for (int i = 0; i < path.length(); i++) {
if (path[i] == '/') {
if (dir == ".") {
}
else if (dir == "..") {
if (!s.empty())
s.pop();
}
else if (dir != "") {
s.push(dir);
}
dir = "";
}
else {
dir += path[i];
}
}
if (dir != "") {
if (dir == ".") {
}
else if (dir == "..") {
if (!s.empty())
s.pop();
}
else if (dir != "") {
s.push(dir);
}
}
if (!s.empty()) {
dir = s.top();
s.pop();
}
else {
return "/";
}
while (!s.empty()) {
dir = s.top() + "/" + dir;
s.pop();
}
dir = "/" + dir;
return dir;
}
};
时间为31.43%,挺慢的,应该是大量使用STL导致的。
68
题意
给你一个数组的单词和一个长度L,把单词排列成若干行,使得每行的宽度都恰好为L。要求每行是两端对齐的(但是最后一行是左对齐),每行贪心地容纳尽可能多的单词;单词之间的空格是平均分布的, 如果不能平均分,则左侧的空位分配更多的空格。保证每个单词的长度不超过L。
分析
遍历数组。可以迅速得出每行能够安排的是哪几个单词。根据单词得出空格的位置和大小即可。
通过运行示例代码得知,如果只有一个词,是左对齐的。
还有少量边界条件需要注意,比如判断是否能够把单词插进当前的这一行。错了几次之后很快就做出来了。
代码
class Solution {
private:
string makeSpaces(int numSpaces, int numIntv, int i) {
int x = numSpaces / numIntv;
if (i < numSpaces % numIntv)
x++;
string ans = "";
while (x--) {
ans += " ";
}
return ans;
}
public:
vector<string> fullJustify(vector<string>& words, int maxWidth) {
vector<vector<string>> lines;
vector<string> ans;
vector<int> sums;
if (words.size() == 0 || maxWidth == 0) {
ans.push_back("");
return ans;
}
vector<string> line;
int sum = 0;
for (int i = 0; i < words.size(); i++) {
// newline
if (sum != 0 && sum + words[i].length() + 1 > maxWidth) {
sum -= line.size() - 1;
lines.push_back(line);
vector<string> newLine;
newLine.push_back(words[i]);
line = newLine;
sums.push_back(sum);
sum = words[i].length();
}
else {
if (sum != 0)
sum++;
sum += words[i].length();
line.push_back(words[i]);
}
}
lines.push_back(line);
sums.push_back(sum);
for (int i = 0; i < lines.size(); i++) {
// single word or last line
if (i == lines.size() -1 || lines[i].size() == 1) {
string a = "";
for (int j = 0; j < lines[i].size(); j++) {
if (a == "")
a = lines[i][j];
else
a += " " + lines[i][j];
}
a += makeSpaces(maxWidth - sums[i], 1, 0);
ans.push_back(a);
}
// distribute spaces
else {
string a = "";
for (int j = 0; j < lines[i].size(); j++) {
if (a == "")
a = lines[i][j];
else
a += makeSpaces(maxWidth - sums[i], lines[i].size() - 1, j - 1) + lines[i][j];
}
ans.push_back(a);
}
}
return ans;
}
};
时间为55.19%,还可以,如果改为遍历一次会更快吧。