题目链接:https://leetcode-cn.com/problems/count-binary-substrings/
这道题目前我有两种解题思路,如果别的小伙伴还有更好的思路或是觉得我的思路不正确,欢迎大家在评论区提出来~
解法1:
export default (str) => {
let r = [];
let match = (str) => {
// 使用正则表达式获取字符串开头的字符
let j = str.match(/^(0+|1+)/)[0];
// 利用“异或”运算将字符反转并复制相同个数
let o = (j[0] ^ 1).toString().repeat(j.length);
// 合并上面两个字符串,创建正则表达式
let reg = new RegExp(`^(${j}${o})`);
// 与传入的字符串进行比对,返回第一个比对成功的子串
if (reg.test(str)) {
return RegExp.$1;
} else {
return '';
}
}
for (let i = 0; i < str.length - 1; i++) {
let sub = match(str.slice(i));
if (sub) {
r.push(sub);
}
}
return r.length;
}
解法1的思路如下:
使用一个for
循环,将字符串从第一个开始传入match
函数中,在match
函数中利用正则表达式获取到字符串开头的字符(或是多个0或是多个1),再使用repeat
方法,将开头获取到的多个0或1利用异或
运算反转重复相同次数(举个例子:获取到了‘00’,那么反转之后就是‘11’),然后再建立一个正则表达式,将获取到的字符和反转后的字符拼接,使用test
方法与传入的字符串进行比对,返回第一个比对成功的字符串,保存到数组r
中。以此类推,剃掉原字符串的第一个字符后再调用一次match
方法,直到原字符串只剩下1个字符,返回数组r的长度,即为题解。
解法2错误思路:
// 错误思路,没有理清指针的关系
export default (str) => {
let result = 0;
let nextcnt = 0;
let precnt = 1;
let len = str.length;
for (let i = 1; i < len - 1; i++) {
if (str[i] === str[i - 1]) {
nextcnt++;
} else {
precnt=nextcnt;
nextcnt=0;
}
if (precnt <= nextcnt) {
result++;
}
}
return result;
}
解法2是本人的一次尝试,希望使用指针的形式将题目解出来,大致思路为使用两个指针记录前半段相同的字符与后半段相同的字符的个数,如果后半段的个数>前半段的个数,那么这一段字符串中必定存在一个子串,计数器++,但是由于本人才疏学浅,思路不清晰,没有理清指针之间的关系,没有通过测试用例。
解法2正确思路:
export default (s) => {
let result = 0;
// curLen 与 preLen 分别记录当前数字出现次数与前半部分数字出现次数,curLen小于等于prLen则符合条件
let curLen = 1;
let preLen = 0;
for (let i = 0; i < s.length - 1; i++) {
// 指针往后移动,若当前数字与下一个数字一样则将curLen加1
if (s[i] === s[i + 1]) {
curLen += 1;
} else {
// 否则就是遇到了不同之处,把相同子串的长度交给preLen,curLen再重新往后寻找
preLen = curLen;
curLen = 1;
}
if (preLen >= curLen) {
result += 1;
}
}
return result;
}
解法2的正确思路是在参考了评论区一些用C/C++、Java写出来的大佬们的思路,与本人的思路大致相同,大佬们思路更加清晰,理清了指针之间的关系。
小结:
解法1是一个很直接很暴力的解法,但是对于ES6的一些基础知识要求比较高,用到slice
、match
、repeat
等方法以及正则表达式,但是由于解法1过于简单暴力,在正则表达式与原字符串进行比对时花费了大量的时间,尤其是原字符串非常长的时候,因此解法1并不是好的算法。
解法2更加符合解题逻辑(个人认为),同时解法2省去了与原字符串比对的过程,因此解法2在时间复杂度上面远比解法1优秀,推荐解法2,但解法2要求思路清晰,能够正确理清指针之间的关系。
解题笔记:
- 复习正则表达式!!!
- 解题思路要清晰,画出原理图找出解题归路,数据结构要用对
repeat
方法可以将字符串复制,参数为复制的次数- 利用异或运算可以做到取反的效果
- 创建正则表达式需要
new RegExp
类,参数为表达式内容,正则表达式内允许有变量,但是需要被${}
包裹 - slice方法可以返回一个新的数组,第一个参数为返回起始点,第二个参数为终点,第一个参数必须,第二个参数可选
- 本题解题思路为:找到传入
match
方法的字符串开头进行解析,含有一个或多个0或1,然后再取反,找到相同个数,拼接为正则表达式,然后将正则表达式与传入的字符串进行比对,返回第一个比对成功的字符串