题目描述:
小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为m|S,例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么?
输入例子1:
"HG[3|B[2|CA]]F"
输出例子1:
"HGBCACABCACABCACAF"
例子说明1:
HG[3|B[2|CA]]F−>HG[3|BCACA]F−>HGBCACABCACABCACAF
这是之前参加腾讯的笔试,遇到的一题,其中我第一次想到的是递归和栈,但是太复杂了。很多细节要考虑,直到看到这个解法,yyds
function compress( str ) {
var a = /\[(\d+)\|([a-zA-Z]+)\]/g
while(str.indexOf("[") >= 0){
str = str.replace(a,(b,$1,$2) =>{
// $1,$2 分别代表的是正则分组匹配结果。
// 2 CA
// 3 BCACA
var result = "";
for(let i = 0; i<$1; i++){
result += $2;
}
return result;
})
}
console.log(str)
}
var str = "HG[3|B[2|CA]]F"
compress(str)
讲解下自己的思路:
写了一个复杂的代码,也是由于替换思想点拨了思路。
先找到左半边的括号 [ ,放进栈里,直到遇到 右半边括号 ], 就弹出栈顶,存入栈是存的左括号的下标,因为思路是替换左半括号和右半括号之间的内容,所以需要开始和结束的下标,直到字符串遍历结束。
代码稍微有点复杂,我会注释讲解
function compress( str ) {
return unzip(str)
}
// 此方法就是替换[ ]之间的内容,包括括号,是在整个字符串上进行替换
var getStr = function (begin, end, arr) {
let num = ''; // 保存压缩次数
let cur = ''; // 保存压缩字符串
let result = ''; //保存解压后的值
// 因为begin是 [ 的下标,所以我从下一位开始,当然就从begin开始也可以的
for (let i = begin + 1; i < end; i++) {
if (arr[i] >= '0' && arr[i] <= '9') {
num = num + arr[i]; // 拿到压缩次数
} else if (arr[i] <= 'Z' && arr[i] >= 'A') {
cur = cur + arr[i]; // 拿到压缩字符
}
}
// 遍历次数解压,得到解压后的字符串 result
while (num) {
result = cur + result;
num--;
}
// 这三句话比较麻烦,我的思路是先把字符转为数组,利用splice方法,例如先删除 [2|CA], 然后插入CACA,就是替换操作了。
arr = arr.split("");
arr.splice(begin, end + 1 - begin, result);
arr = arr.join("");
// 为什么需要返回now, 是为了让遍历从替换后的字符开始重新寻找括号,然后直到全部替换完!!!
// arr : HG[3|BCACA]F
return { arr, now: begin + result.length }
}
var unzip = function (str) {
let stack = [];
let begin = 0;
let i = 0;
let len = str.length;
// 开始使用的for循环来遍历,发现不好更改遍历的值 i ,换成while了。
while (i < len) {
if (str[i] == ']') {
begin = stack.pop(); // 出栈顶
const { arr, now } = getStr(begin, i, str); // 得到替换的最新字符串,
str = arr; // 更新字符串
i = now - 1; // 让i从替换后的位置开始遍历
} else if (str[i] == '[') {
stack.push(i); // 入栈左括号
}
i++;
}
return str // 得到的就是解压缩后的字符串
// "HGBCACABCACABCACAF"
}