题目
- 如,输入 ‘abbcccddeeee1234’,计算得到:
- 连续最多的字符是 ‘e’,4次
传统思路
- 嵌套循环,找出每个字符的连续次数,并记录
- 看似时间复杂度是O(n^2)
- 但实际复杂度是O(n),因为有 “跳步”
双指针
- 定义指针 i 和 j。j 不动,i继续移动
- 如果 i 和 j 的值一直相等,则 i 继续移动
- 直到 i 和 j 的值不相等,记录处理,让 j 追上 i
/**
* @description 找出字符串中连续最多的字符,以及次数
* @author lsr
*/
interface IRes {
char: string
length: number
}
/**
* 找出字符串中连续最多的字符,以及次数 - 嵌套循环
* @param str
* @returns
*/
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.length = tempLength
res.char = str[i]
}
// 跳步
if (j < length - 1) {
i = j - 1
}
break
}
}
}
return res
}
/**
* 找出字符串中连续最多的字符,以及次数 - 双指针
* @param str
* @returns
*/
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) {
// 与返回值做对比
if (tempLength > res.length) {
res.char = str[j]
res.length = tempLength
}
// 重置临时记录
tempLength = 0
if (i < length - 1) {
j = i // 让“j”追上“i”
i--
}
}
}
return res
}
// 功能测试
// const str1 = 'abbcccddeeee1234'
// const res1 = findContinuousChar1(str1)
// console.log(res1)
// const str2 = 'abbcccddeeee1234'
// const res2 = findContinuousChar2(str2)
// console.log(res2)
// 性能测试
let str = ''
for (let i = 0; i < 100 * 10000; i++) {
str += i.toString()
}
console.time('findContinuousChar1')
findContinuousChar1(str)
console.timeEnd('findContinuousChar1') // 127.184814453125 ms
console.time('findContinuousChar2')
findContinuousChar2(str)
console.timeEnd('findContinuousChar2') // 129.971923828125 ms
单元测试
/**
* @description 找出字符串中连续最多的字符,以及次数 test
* @author lsr
*/
import {
findContinuousChar1,
findContinuousChar2
} from '@/01-algorithm/continuous-char'
describe('找出字符串中连续最多的字符,以及次数', () => {
it('最多连续字符在中间', () => {
const str = 'abbcccddeeee1234'
const res = findContinuousChar2(str)
expect(res).toEqual({
char: 'e',
length: 4
})
})
it('最多连续字符在开头', () => {
const str = 'aaaaabbcccddeee1234'
const res = findContinuousChar2(str)
expect(res).toEqual({
char: 'a',
length: 5
})
})
it('最多连续字符在结尾', () => {
const str = 'aaaaabbcccddeee123444444'
const res = findContinuousChar2(str)
expect(res).toEqual({
char: '4',
length: 6
})
})
it('空字符串', () => {
const str = ''
const res = findContinuousChar2(str)
expect(res).toEqual({
char: '',
length: 0
})
})
it('无连续字符', () => {
const str = 'abcdefg'
const res = findContinuousChar2(str)
expect(res).toEqual({
char: 'a',
length: 1
})
})
it('全都是连续字符', () => {
const str = 'aaaaa'
const res = findContinuousChar2(str)
expect(res).toEqual({
char: 'a',
length: 5
})
})
})
划重点
- 要注意实际复杂度,不要被代码表面迷惑
- 双指针常用于解决嵌套循环
- 算法题慎用正则表达式(实际工作可用)