算法:获取字符串中连续最多的字符及次数

26 阅读1分钟

传统思路

  • 嵌套循环,找出每个字符串的连续次数,并记录
  • 看似时间复杂度是O(n^2)
  • 但实际时间复杂度是多少?---O(n) 因为有跳步

image.png

嵌套循环思路代码:

interface IRes {
  char: string
  length: number
}

function findContinuousChar1(str: string): IRes {
  const res: IRes = {
    char: '',
    length: 0,
  }
  const length = str.length
  if (length === 0) return res

  let tempLength = 0 // 临时记录当前连续字符的长度

  for (let i = 0; i < length; i++) {
    tempLength = 0 // 重置

    for (let j = i; i < length; j++) {
      if (str[i] === str[j]) {
        tempLength++
      }
      if (str[i] !== str[j] || j === length - 1) {
        // 不相等,或者已经到了最后一个元素,要去判断最大值
        if (tempLength > res.length) {
          res.char = str[i]
          res.length = tempLength
        }

        if (i < length - 1) {
          i = j - 1 // 跳步
        }
        break
      }
    }
  }
  return res
}

// 功能测试

const str = 'aabbcccddeeee11223'

console.info(findContinuousChar1(str))

结果:

image.png

双指针思路 O(n)

  • 定义指针i和j。j不动,i继续移动
  • 如果i和j的值一直相等,则i继续移动
  • 指导i和j的值不相等,记录处理,让j追上i。继续第一步
function findContinuousChar2(str: string): IRes {
  const res: IRes = {
    char: '',
    length: 0,
  }
  const length = str.length
  if (length === 0) return res

  let tempLength = 0 // 临时记录当前连续字符的长度

  let i = 0
  let j = 0
  for (; i < length; i++) {
    if (str[i] === str[j]) {
      tempLength++
    }

    if (str[i] !== str[j] || i === length - 1) {
      // 不相等, 或者 i 到了字符串的末尾
      if (tempLength > res.length) {
        res.char = str[j]
        res.length = tempLength
      }
      tempLength = 0 // reset
      if (i < length - 1) {
        j = i // 让j 追上i
        i-- // 细节
      }
    }
  }
  return res
}
// 功能测试

const str = 'aabbcccddeeee11223'
console.info(findContinuousChar2(str))

网络上其他方式

  • 正则表达式-效率非常低,慎用
  • 累计各个元素的连续长度,最后求最大值 --- 徒增空间复杂度
  • 算法题尽量用“低级”代码,慎用语法糖或者高级API
const str1 = '100abc'
const reg = /^\d+/

console.time('reg')
for (let i = 0; i < 100 * 10000; i++) {
  reg.test(str1)
}
console.timeEnd('reg') // 23ms 正则表达式太慢了

console.time('indexOf')
for (let i = 0; i < 100 * 10000; i++) {
  str1.indexOf('100')
}
console.timeEnd('indexOf') // 2ms

划重点

  • 要注意实际复杂度,不要被代码表面迷惑
  • 双指针常用于解决嵌套循环
  • 算法题慎用正则(工作中可用)