双指针算法在实际开发中的具体应用之代码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 树遍历等

对撞指针应用场景

  • 回文字符串验证
  • 有序数组的两数之和
  • 数组元素交换等
相关推荐
weixin_499771551 分钟前
C++中的组合模式
开发语言·c++·算法
iAkuya32 分钟前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼32 分钟前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck34 分钟前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl
松☆38 分钟前
CANN与大模型推理:在边缘端高效运行7B参数语言模型的实践指南
人工智能·算法·语言模型
java干货1 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
皮皮哎哟1 小时前
数据结构:嵌入式常用排序与查找算法精讲
数据结构·算法·排序算法·二分查找·快速排序
程序员清洒1 小时前
CANN模型剪枝:从敏感度感知到硬件稀疏加速的全链路压缩实战
算法·机器学习·剪枝
vortex51 小时前
几种 dump hash 方式对比分析
算法·哈希算法
Wei&Yan2 小时前
数据结构——顺序表(静/动态代码实现)
数据结构·c++·算法·visual studio code