双指针算法在实际开发中的具体应用之代码Review文章字符串的片段分割

本文是笔者在实际中具体遇到的场景,从中提取具体的核心的部分,使用前后指针进行性能优化的具体案例

开发需求场景

  • 前段时间,笔者在做代码Review的时候,发现了一个需求的前端实现方案不太优雅
  • 组员选择使用了循环加切割的方案去处理这个字符串
  • 笔者最终将其改为,使用快慢指针的方式,让其变得更加优雅,性能更佳

需求描述

  • 后端有一个字段返回一篇中文文章的具体内容
  • 比如有一个artical文章字段的值是一个长长的字符串
  • 需求抽象成:let artical = '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。'
  • 前端展示的时候,需要一行一行展示(标点符号分隔,一句话就是一行)
  • 比如上述的artical的值,最终会展示成
html 复制代码
<p>白日依山尽</p>
<p>黄河入海流</p>
<p>欲穷千里目</p>
<p>更上一层楼</p>

循环加切割的方案

他的实现思路是:

先第一遍遍历,把原来的字符串"拷贝"一份,如果遇到了标点符号,统一使用横杠替换,最后再以横杠为标识,将字符串切割成数组,从而完成需求

实际上的标点符号,除了逗号、句号之外,还有问号,感叹号,省略号等,这里是为了更便于理解,抽象成为简单模型

代码

js 复制代码
let artical = '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。'

function toArr(str) {
    let s = [',', '。']
    let ns = ''
    for (let i = 0; i < str.length - 1; i++) {
        if (s.includes(str[i])) {
            ns = ns + '-'
        } else {
            ns = ns + str[i]
        }
    }
    return ns.split('-')
}

const result = toArr(artical)
console.log('result', result)

点评

  • 首先,时间复杂度高,每次拼接都会复制整个已有字符串,字符串越长,复制的成本越高,累积起来甚至达到平方级的耗时。而artical字段的值,也不小,所以这种拼接方式效率不太高
  • 然后,有依赖特殊字符风险,若原字符串中本身包含 -,那么split('-') 则是会错误分割,尴尬了

快慢双指针方案

实现思路是

  • 定义两个指针lr,初始都在起点索引为0的地方
  • 使用while循环,让第一个指针r先往右跑
  • r遇到标点符号的时候,截取lr的区间的字符串存到数组里面
  • 而后,再让l赶上rr再往右跑,直到跑到头,跑完整个article字符串
  • 有点像,张三和李四拿着卷尺丈量操场的长度
  • 李四原地不动,张三拉着卷尺到头,记录一段距离
  • 李四再跑到张三的位置,张三再往前跑同时把卷尺拉到头
  • 如下动画:

代码

js 复制代码
let artical = '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。'

function toArr(str) {
    let s = [',', '。']
    let arr = []
    let l = 0
    let r = 0
    while (r <= str.length - 1) {
        if (s.includes(str[r])) {
            let range = str.slice(l, r)
            arr.push(range)
            r = r + 1
            l = r
        } else {
            r = r + 1
        }
    }
    return arr
}
const result = toArr(artical)
console.log('result', result)

最终使用Set集合去判断是否是标点符号,即

js 复制代码
function toArr(str) {
    let s = new Set([',', '。'])
    let arr = []
    let l = 0
    let r = 0
    while (r <= str.length - 1) {
        if (s.has(str[r])) {
            let range = str.slice(l, r)
            arr.push(range)
            r = r + 1
            l = r
        } else {
            r = r + 1
        }
    }
    return arr
}

点评

  • 时间复杂度整体保持O(n)------n 为字符串长度【从头到尾跑一遍就行了】
  • 空间复杂度没大的开销
  • Set的语义更贴合 "判断元素是否在一个集合中" 的场景,代码清晰------Set天然用于去重和成员判断
  • 数组includes的效率会随标点符号数量增多而下降

A good memory is better than a bad pen. Record it down... 最后,再来回顾一下双指针的相关知识

双指针知识回顾

  • 双指针是相对于单指针而言的,我们常见的for循环和forEach只有一个索引变量i的,就是单指针,有两个变量,比如i或者j的,就是双指针
  • 双指针的本质是多定义一个索引变量j,用空间换时间提升效率的方式
  • 双指针分为快慢指针和对撞指针
    • 快慢指针------两个指针同侧出发移动,一前一后,一快一慢
    • 对撞指针------两个指针从两端向中间移动

快慢指针应用场景

  • 链表操作(判断循环、找中间节点)
  • 数组去重、字符串处理(本文就是一个具体实际应用)
  • DOM 树遍历等

对撞指针应用场景

  • 回文字符串验证
  • 有序数组的两数之和
  • 数组元素交换等
相关推荐
多喝开水少熬夜18 小时前
Trie树相关算法题java实现
java·开发语言·算法
WBluuue18 小时前
数据结构与算法:树上倍增与LCA
数据结构·c++·算法
bruk_spp19 小时前
牛客网华为在线编程题
算法
黑屋里的马21 小时前
java的设计模式之桥接模式(Bridge)
java·算法·桥接模式
sin_hielo21 小时前
leetcode 1611
算法·leetcode
李小白杂货铺21 小时前
识别和破除信息茧房
算法·信息茧房·识别信息茧房·破除信息茧房·算法推荐型茧房·观点过滤型茧房·茧房
来荔枝一大筐1 天前
C++ LeetCode 力扣刷题 541. 反转字符串 II
c++·算法·leetcode
暴风鱼划水1 天前
算法题(Python)数组篇 | 6.区间和
python·算法·数组·区间和
zl_vslam1 天前
SLAM中的非线性优-3D图优化之轴角在Opencv-PNP中的应用(一)
前端·人工智能·算法·计算机视觉·slam se2 非线性优化
是苏浙1 天前
零基础入门C语言之C语言实现数据结构之顺序表应用
c语言·数据结构·算法