【LeetCode-中等】722. 删除注释

题目链接

722. 删除注释

标签

字符串

步骤

Step1. 先将source合并为一个字符串进行处理,中间补上’\n’,方便后续确定注释开始、结束位置。

string combined;
for (auto str : source) {
    combined += str + "\n";
}

Step2. 定义数组 toDel,记录每一个注释开始、结束的位置;进行状态转移。对于 /**/ 类型的注释的结束符 */,如果匹配失败,则需要回退一位。

状态转移表示如下:

s0: if /: goto s1 # match /, change to s1
    else: goto s0
s1: if /: cut down this line, goto s0 # match //
    elif *: goto s2 # match /*
    else: goto s0 # match failed, return to s1
s2: if *: goto s3 # match * in comment; s2 means that the current state is InComment
    else: goto s2
s3: if /: end this comment, goto s0 # match */
    else: goto s3  # match failed, return to s2

具体的代码部分如下:

for (int i = 0; i < len; i++) {
    char ch = combined[i];
    switch (state) {
        case 0:
            if (ch == '/') {
                state = 1;
            } else {
                state = 0;
            }
            break;
        case 1:
            if (ch == '/') { // 出现//,删去此行之后的内容
                // 找到从当前下标开始的第一个\n,下一次遍历从其之后开始
                int end = combined.find("\n", i);
                cmtBegin = i - 1;
                cmtEnd = end - 1;
                toDel.push_back({cmtBegin, cmtEnd});
                
                state = 0;
                i = end;
            } else if (ch == '*') { // 出现/*
                state = 2;
                cmtBegin = i - 1;
            } else {
                state = 0;
            }
            break;
        case 2:
            if (ch == '*') {
                state = 3;
            } else {
                state = 2;
            }
            break;
        case 3:
            if (ch == '/') { // cmtEnd
                state = 0;
                cmtEnd = i;
                toDel.push_back({cmtBegin, cmtEnd});
            } else { // 匹配*/失败,回退一位
                state = 2;
                i--;
            }
            break;
    } 
}

Step3. 遍历 toDel,得到不含注释的中间结果 tmpAns

// 遍历toDel,得到删除注释的中间结果
string tmpAns;
int last = 0;
for (auto p : toDel) {
    // 下标a和b-1之间的长度:b-a
    tmpAns += combined.substr(last, p.first - last);
    last = p.second + 1;
}
// 分为toDel.size()+1段的最后一段
tmpAns += combined.substr(last, combined.length() - last);

Step4. 根据 \n 来分割 tmpAns 即可。

vector<string> ans;
int pos = tmpAns.find("\n", 0);
while (pos != string::npos) {
    if (pos != 0) {
        ans.push_back(tmpAns.substr(0, pos));
    }
    tmpAns.erase(0, pos+1);
    pos = tmpAns.find("\n", 0);
}

实现代码(C++)

class Solution {
public:
    vector<string> removeComments(vector<string>& source) {
        int state = 0;
        // 合并为一个字符串
        string combined;
        for (auto str : source) {
            combined += str + "\n";
        }

        vector<pair<int,int>> toDel;
        int len = combined.length();
        int cmtBegin = -1, cmtEnd = -1;
        for (int i = 0; i < len; i++) {
            char ch = combined[i];
            switch (state) {
                case 0:
                    if (ch == '/') {
                        state = 1;
                    } else {
                        state = 0;
                    }
                    break;
                case 1:
                    if (ch == '/') { // 出现//,删去此行之后的内容
                        // 找到从当前下标开始的第一个\n,下一次遍历从其之后开始
                        int end = combined.find("\n", i);
                        cmtBegin = i - 1;
                        cmtEnd = end - 1;
                        toDel.push_back({cmtBegin, cmtEnd});
                        
                        state = 0;
                        i = end;
                    } else if (ch == '*') { // 出现/*
                        state = 2;
                        cmtBegin = i - 1;
                    } else {
                        state = 0;
                    }
                    break;
                case 2:
                    if (ch == '*') {
                        state = 3;
                    } else {
                        state = 2;
                    }
                    break;
                case 3:
                    if (ch == '/') { // cmtEnd
                        state = 0;
                        cmtEnd = i;
                        toDel.push_back({cmtBegin, cmtEnd});
                    } else { // 匹配*/失败,回退一位
                        state = 2;
                        i--;
                    }
                    break;
            } 
        }

        // 遍历toDel,得到删除注释的中间结果
        string tmpAns;
        int last = 0;
        for (auto p : toDel) {
            tmpAns += combined.substr(last, p.first - last);
            last = p.second + 1;
        }
        tmpAns += combined.substr(last, combined.length() - last);

        // 根据\n分割
        vector<string> ans;
        int pos = tmpAns.find("\n", 0);
        while (pos != string::npos) {
            if (pos != 0) {
                ans.push_back(tmpAns.substr(0, pos));
            }
            tmpAns.erase(0, pos+1);
            pos = tmpAns.find("\n", 0);
        }

        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值