题目:给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。重复出现的子串要计算它们出现的次数。

输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
请注意,一些重复出现的子串要计算它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-binary-substrings
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

算法的本质是寻找规律并实现。 而实现是程序+数据结构的结合体。 规律是找到输入和输出的关系
  • 寻找规律: 通过图示法发现规律所在,从上图可以看出每次匹配到的结果都是向后移一位的,所以这里可以考虑使用递归或循环处理,每次循环用当前的数字与后面的数字做比对,符合结果就返回。

所以这里我们先使把数据结构写出来,嗯,清晰很多了。

    // 循环进行移位, length-1 是因为根据题意要求必须连续,最后一位数无其他可匹配对象,不可能会符合连续的要求
    for (let i = 0; i < s.length - 1; i++) {
        // 每次循环需要与剩余的数字进行比对,所以这里封装函数处理
        let matchNUm = match(s.slice(i))
        if (matchNUm) arr.push(matchNUm)
    }
  • 算法实现: 找出字符中数量的连续1和0
//匹配要找的子串
  var match = (str) => {
    //  先找出相同数量连续的1和0
    let j = str.match(/^(0+|1+)/)[0]
    // 找出相对应的数量连续的 0 或者 1
    // console.log(j) //  00、0、11、1、00、0、11
    // ^ 位操作符:按位异或(XOR)对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。(也就是取反)
    // 取反后需保证与 j 的个数相同,所以利用repeat函数做重复处理
    let o = (j[0] ^ 1).toString().repeat(j.length)
    // console.log(o) // 11、1、00、0、11、1、00   与 j的值刚好相反

    // 此时 j+o 便是我们要找的子串,如何进行匹配呢,使用正则处理?
    let reg = new RegExp(`^(${j}${o})`)
    // console.log(reg, reg.test(str))
    if (reg.test(str)) {
      return RegExp.$1
    }
  }

整体代码

export default (s) => {
  var arr = [] // 用来存储匹配到的子串

  /**
   * 匹配要找的子串
   * @param {*} str
   */
  var match = (str) => {
    //  先找出相同数量连续的1和0
    let j = str.match(/^(0+|1+)/)[0]
    // 找出相对应的数量连续的 0 或者 1
    // console.log(j) //  00、0、11、1、00、0、11
    // ^ 位操作符:按位异或(XOR)对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。(也就是取反)
    // 取反后需保证与 j 的个数相同,所以利用repeat函数做重复处理
    let o = (j[0] ^ 1).toString().repeat(j.length)
    // console.log(o) // 11、1、00、0、11、1、00   与 j的值刚好相反

    // 此时 j+o 便是我们要找的子串,如何进行匹配呢,使用正则处理?
    let reg = new RegExp(`^(${j}${o})`)
    // console.log(reg, reg.test(str))
    if (reg.test(str)) {
      return RegExp.$1
    }
  }

  // 循环进行移位
  // length-1 是因为根据题意要求必须连续,最后一位数无其他可匹配对象,不可能会符合连续的要求
  for (let i = 0; i < s.length - 1; i++) {
    // 每次循环需要与剩余的数字进行比对,所以这里封装函数处理
    let matchNUm = match(s.slice(i))
    if (matchNUm) arr.push(matchNUm)
  }

  console.log('找到的子串为', arr)
  return arr
}
在线运行

史瓦辛格
820 声望215 粉丝