isaacpei / algorithm-interview

Weekly algorithm questions for interview
18 stars 0 forks source link

Q001_ryanorz_c++_solution: no error check, no tag match, just simple enough. #1

Open ryanorz opened 6 years ago

ryanorz commented 6 years ago

Question_ID: Q001_ryanorz_solution

Language: c++

Time Cost: 40-mins

Time Complexity: O(n)

Solution

Note: no error check, no tag match, just simple enough.

  1. First, get token with 4 types(Content, Pretag, Posttag, Fulltag), my solution does't have error input check yet.
  2. Then, output token

My Code

响应号召,代码变成30行以内

#include <string>
using namespace std;

void formatXML3(const string& input) {
    int offset = 0;
    int level = 0;
    while (offset < input.size()) {
        int start = offset;
        if (input[offset] == '<') // 找出 tag
            offset = input.find_first_of(">", offset+1) + 1;
        else // 找出 content
            offset = input.find_first_of("<", offset+1);
        if (offset == string::npos) // 没找到结尾符号则,则直接偏移到最后
            offset = input.size();
        // </tag> 结尾标签层级先减一再打印
        if (input[start] == '<' && input[start+1] == '/') level--;
        // 打印 level + tag 或 level + content
        printf("%s%s\n", string(level*4, ' ').c_str(),
            input.substr(start, offset-start).c_str());
        // <tag> 开始标签打印完层级加一
        if (input[start] == '<' && input[start+1] != '/' && input[offset-2] != '/') level++;
    }
}

int main(int argc, char* argv[]) {
    string input = "<a>123<b>456<c/></b></a>";
    formatXML3(input);
}

以下是原始版代码

#include <string>
using namespace std;

enum class TokenType {
    Content,
    Pretag,
    Posttag,
    Fulltag
};

string getNextTokenWithoutErrorCheck(string& xmlWithoutFormat, int& offset, TokenType& type) {
    int size = xmlWithoutFormat.size();
    if (offset >= size) return "";
    int start = offset;
    switch (xmlWithoutFormat[start]) {
    case '<':
        while (xmlWithoutFormat[offset] != '>') {
            offset++;
        }
        if (xmlWithoutFormat[offset-1] == '/') {
            type = TokenType::Fulltag;
        } else if (xmlWithoutFormat[start+1] == '/') {
            type = TokenType::Posttag;
        } else {
            type = TokenType::Pretag;
        }
        offset++;
        break;
    default:
        while (xmlWithoutFormat[offset] != '<' && offset < size) {
            offset++;
        }
        type = TokenType::Content;
    }
    return xmlWithoutFormat.substr(start, offset - start);
}

void formatXML(string& xmlWithoutFormat) {
    int level = 0;
    int offset = 0;
    TokenType type;
    while (true) {
        string token = getNextTokenWithoutErrorCheck(xmlWithoutFormat, offset, type);
        if (token.size() == 0) break;
        switch (type) {
        case TokenType::Content:
        case TokenType::Fulltag: {
            for (int i = 0; i < level; i++) printf("\t");
            printf("%s\n", token.c_str());
            break;
        }
        case TokenType::Pretag: {
            for (int i = 0; i < level; i++) printf("\t");
            printf("%s\n", token.c_str());
            level++;
            break;
        }
        case TokenType::Posttag: {
            level--;
            for (int i = 0; i < level; i++) printf("\t");
            printf("%s\n", token.c_str());
            break;
        }
        }
    }
}

int main(int argc, char* argv[]) {
    string input = "<a>123<b>456<c/></b></a>";
    formatXML(input);
}

Other

isaacpei commented 6 years ago

感觉简化的代码不错啊~ 就是花的时间长了点, 希望压缩在20分钟以内, 另外思路感觉表述的太简单了, 建议在某种情况level该加该减最好说一下