一道腾讯前端面试题解压字符串的思考

498 阅读4分钟

题目描述

给出一个字符串,其中有这样一个特殊情况[number|string],其中number表示重复的字数,string表示需要重复的字符串

示例:

输入:a[2|bc]d
输出:abcbcd

解题思路

首先考虑到的是,肯定不会通过分析每个字符去执行响应的操作,那样就把问题复杂化了,有经验的开发者首先就会想到正则来处理这种情况,即用replace()方法来处理

最简单的情况

function deStr(str) {
    let reg = /\[(\d+)\|(\w+)\]/g;
    return str.replace(reg, function(match, repCount, matchedStr) {
        return matchedStr.repeat(repCount);
    })
}

这个方案能够处理一层模板的情况,但是匹配的字符串里面有嵌套呢,如[2|a[3|b]],显然这样的方案就不合适了,需要仅需改进

处理嵌套模板

function deStr(str) {
    let reg = /\[(\d+)\|(.+)\]/g;
    if (!reg.test(str)) {
        return str;
    }
    return str.replace(reg, function(match, repCount, matchedStr) {
        let handledStr = deStr(matchedStr);
        return handledStr.repeat(repCount);
    })
}

修改了一下正则表达式,匹配|后面的所有字符,然后加上递归的方式解决嵌套的模板,这套方案还存在着问题,不能兼容一个字符串中包含多个模板,如[2|a][3|b]这种情况

处理同级模板

在这里,我就陷入沉思了,我们既要处理嵌套的情况,又要处理同级的情况,应该怎么办?

  1. 抛开正则,通过分析分隔符的下标,将[]用一个栈保存起来,如果是[就push进去,如果是]就弹出了,这样就可以解决左右分隔符不对应的情况,但是问题似乎被复杂化了,因为你不知道左右分隔符的具体顺序,还得分析每一个下标的大小,再进行相应的配对
  2. 改进左右分隔符的匹配,重新思考,逆向思维,我们如果从左到右检索[的位置,但是不知道下一个符号应该出现[还是],但是我们从左向右检索]的位置,却可以确定在此之前的一个符号肯定是[与之对应,所以我们就能够轻松的讲模板分隔出来
function deStr(str) {
    let rightIndex = -1;
    while ((rightIndex = str.indexOf(']')) !== -1) {
        let leftIndex = str.lastIndexOf('[', rightIndex);
        let subStr = str.substring(leftIndex, rightIndex + 1);
        str = str.replace(subStr, deOneTemp(subStr));
    }
    return str;
}

function deOneTemp(str) {
    let reg = /\[(\d+)\|(\w+)]/;
    return str.replace(reg, function(match, repCount, matchedStr) {
        return matchedStr.repeat(repCount);
    });
}

这个方案勉强能够解决问题,但是每次匹配一个模板都需要用到两次indexOf()去匹配,indexOf()底层也是通过遍历去实现的,并且这种属于自底向上的解决方式,越到后面,需要检索的字符个数就越多,所以从时间复杂度来说,这种方案还是有点欠妥

最终解决方案

又回到我们刚开始的思考,正则匹配是有一个全局模式的,所以天然具有处理同级的能力,但很难却解决嵌套问题,但是我们函数却可以递归呀,代码如下

function deStr(str) {
    let reg = /\[(\d+)\|(\w+)\]/g;
    if (!reg.test(str)) {
        return str;
    }
    let result = str.replace(reg, function(match, repCount, matchedStr) {
        return matchedStr.repeat(repCount);
    });
    return deStr(result);
}

看到这里,是不是感觉特别简单!!!

感受

这是第一次做腾讯的实习招聘题,同时也是第一次尝试到,自己努力了两年,对前端的一种热爱,但是被否定了。这次腾讯到我们学校的笔试题就是5道算法题,根据就没有考前端相关的知识,可能别人认为你是一个应届生,不相信你的能力有多强,我只在乎你的基础,在乎你的逻辑能力。其实我以前一直以为算法没有那么重要,因为自己做过一些算法,一般的算法都不难,我一直认为只要不犯逻辑上的错误,题目都能够解决出来,并且也能够分析出哪些还可以继续优化,存在边界没有考虑到的情况,一切只是时间问题,如果时间够,肯定能交出一个满意的算法,还有一个看法,就是一些优秀的算法都是一些奇淫技巧,这些东西也只能靠自己积累,所以感觉算法不是那么重要。这次因为自己平时没有积累算法,算是失去了这次机会,大的公司需要你具有好的算法能力,也只能去适应这个环境吧,春招加油!!!