Leetcode 696.計數二進制子串(javascript)

題目

給定一個字符串 s,計算具備相同數量0和1的非空(連續)子字符串的數量,而且這些子字符串中的全部0和全部1都是組合在一塊兒的。數據結構

重複出現的子串要計算它們出現的次數。ui

示例1:spa

輸入: "00110011"
輸出: 6
解釋: 有6個子串具備相同數量的連續1和0:「0011」,「01」,「1100」,「10」,「0011」 和 「01」。

請注意,一些重複出現的子串要計算它們出現的次數。

另外,「00110011」不是有效的子串,由於全部的0(和1)沒有組合在一塊兒。
複製代碼

注意:code

s.length 在1到50,000之間。
s 只包含「0」或「1」字符。
複製代碼

思路1 (暴力枚舉)

解1

e.g. s= '110011', s.length = 6 reg的可取值 /01/g 或/10/g, /0011/g或/1100/g, /000111/g或/111000/g 步驟:regexp

  1. 動態拼接reg
  2. 全部reg對應的s.match(reg).length求和就是所求子串的數量
const countBinarySubstrings = function (s) {
  const len = s.length
  let count = 0
  let s1 = ''
  let s2 = ''
  for (let index = 1; index <= Math.floor(len / 2); index++) {
    s1 += '0'
    s2 += '1'
    let res1 = s.match(new RegExp(s1 + s2, 'g')) || []
    let res2 = s.match(new RegExp(s2 + s1, 'g')) || []
    count += res1.length
    count += res2.length
  }

  return count
}

複製代碼

解2

序號 過程
輸入 00110011
1 00110011
2 00110011
3 00110011
4 00110011
5 00110011
6 00110011

須要兩次循環: 外循環: 從頭至尾遍歷每一個字母, 內循環: 第i輪: subStri = s.slice(i), 從頭開始匹配符合規則的子串 時間複雜度O(n^2)字符串

const countBinarySubstrings = (str) => {
  // 創建數據結構,堆棧,保存數據
  let r = 0
  // 給定任意子輸入都返回第一個符合條件的子串
  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 true
    }
    return false
  }
  // 經過for循環控制程序運行的流程
  for (let i = 0, len = str.length - 1; i < len; i++) {
    let sub = match(str.slice(i))
    if (sub) {
      r++
    }
  }
  return r
}

複製代碼

思路2 (換一種表示)

字符串 用連續0或1的個數表示 子串個數
00110011 2222 min(2, 2) + min(2, 2) + min(2, 2) = 6
001100 221 min(2, 2) + min(2, 1) = 3

步驟:get

  1. 轉爲連續子串個數形式 e.g. 「1111000011010001011」轉化爲[4, 4, 2, 1, 1, 3, 1, 1, 2]
  2. 相鄰元素min求最小值再求和
const countBinarySubstrings = (s) => {
  const resArr = []
  let cnt = 0
  let last = s.length - 1
  // i屬於 [0, last-1]
  for (let i = 0; i < last; i++) {
    cnt++
    if (s[i] != s[i + 1]) {
      resArr.push(cnt)
      cnt = 0
    }
  }
  // 最後一位特殊處理
  if (s[last - 1] == s[last]) {
    resArr.push(cnt + 1)
  } else {
    resArr.push(1)
  }
  
  // 相鄰元素min求最小值再求和
  let sum = 0
  for (let i = 0; i < resArr.length - 1; i++) {
    sum += Math.min(resArr[i], resArr[i + 1])
  }
  return sum
}


複製代碼

思路3 (標記)

時間複雜度O(n)博客

const countBinarySubstrings = (s) => {
  let last = 0 // last 上一次連續的個數
  let cur = 0 // cur 當前數字連續的個數
  let count = 0  // 符合規則子串的數量
  let len = s.length
  for (let i = 0; i < len - 1; i++) {
    cur++
    if (last >= cur) {
      count++
    }
    if (s[i] != s[i + 1]) {
      last = cur
      cur = 0
    }
  }

  // 最後一位狀況
  // cur ==0 <=> 後兩位不一樣
  if (cur == 0) {
    cur = 1
  } else {
    cur++
  }

  if (last >= cur) {
    count++
  }

  return count
}

複製代碼

givencui博客首發, 轉載請註明來自GivenCuistring

相關文章
相關標籤/搜索