连续最多的字符
题目
给一个字符串,找出连续最多的字符,以及次数。
例如字符串 'aabbcccddeeee11223' 连续最多的是 e ,4 次。
传统方式
嵌套循环,找出每个字符的连续次数,并记录比较。
时间复杂度看似是 O(n^2),因为是嵌套循环。 但实际上它的时间复杂度是 O(n),因为循环中有跳转。
双指针
- 定义指针 i 和 j。j 不动,i 继续移动。
- 如果 i 和 j 的值一直相等,则 i 继续移动。
- 直到 i 和 j 的值不相等,记录处理,让 j 追上 i。继续第一步。
只有一次循环,时间复杂度是 O(n)
性能测试,发现两者时间消耗一样,循环次数也一样。
其他方式
这个题目网上还有其他的答案
- 正则表达式 —— 正则表达式的效率非常低,可进行性能测试
- 使用数组累计各个字符串的长度,然后求出最大值 —— 增加空间复杂度,面试官不会喜欢
【注意】算法尽量用基础代码实现,尽量不要用现成的 API 或语法糖 —— 方便,但你不好直观判断时间复杂度
答案
上述两种方式(嵌套循环和双指针)都可以。
循环嵌套:
interface IRes {
char: string
length: number
}
/**
* 求连续最多的字符和次数(嵌套循环)
* @param str str
*/
export function findContinuousChar1(str: string): IRes {
const res: IRes = {
char: '',
length: 0
}
const length = str.length
if (length === 0) return res
let tempLength = 0 // 临时记录当前连续字符的长度
// O(n)
for (let i = 0; i < length; i++) {
tempLength = 0 // 重置
for (let j = i; j < 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
}
双指针:
/**
* 求连续最多的字符和次数(双指针)
* @param str str
*/
export 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
// O(n)
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 = '100abc'
const reg = /^\d+/
console.time('reg')
for (let i = 0; i < 100 * 10000; i++) {
reg.test(str)
}
console.timeEnd('reg') // 28 ms
console.time('indexOf')
for (let i = 0; i < 100 * 10000; i++) {
str.indexOf('100')
}
console.timeEnd('indexOf') // 2 ms