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 a(1, 1);
        vector 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 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 fullJustify(vector& words, int maxWidth) {
        
        vector> lines;
        vector ans;
        vector sums;
        
        if (words.size() == 0 || maxWidth == 0) {
            ans.push_back("");
            return ans;
        }
        
        vector 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 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%,还可以,如果改为遍历一次会更快吧。

你可能感兴趣的:(Leetcode刷题总结(2):字符串问题)