LeetCode简单算法计数二进制子串

29次阅读

共计 1829 个字符,预计需要花费 5 分钟才能阅读完成。

题目:给定一个字符串 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
}

在线运行

正文完
 0