Java 基于字符串相关知识点

一、字符串的存储与表示

表示方式 结构特点 示例语言/环境

C 风格(以 \0 结尾) 需遍历找结束符,长度 O(n),易溢出 C/C++ 字面量

Pascal 风格(长度前缀) 第一个字节存储长度,最大 255 Delphi / 老式 Pascal

带长度与容量结构 独立存储 len 和 cap,支持动态扩容 C++ std::string,Rust String

短字符串优化 (SSO) 小字符串存放在对象内部栈上,避免堆分配 libstdc++、LLVM libc++

写时复制 (COW) 共享数据,修改时才复制(已少用) 旧版 GCC std::string

二、字符编码

编码 特点 陷阱

ASCII 7 位,128 个字符 无法表示中文等

GB2312 / GBK 中文双字节,兼容 ASCII 与 UTF‑8 互认乱码

UTF‑8 变长 1~4 字节,兼容 ASCII 字符 ≠ 字节,需正确处理多字节

UTF‑16 2 或 4 字节,Windows 常用 代理对(surrogate pair)

UTF‑32 定长 4 字节,简单但空间大 内存浪费

BOM (Byte Order Mark) U+FEFF,标识大小端 某些协议/JSON 不建议使用

关键点:

· len() 在不同语言中可能是字节数(Go/C)、码点数(Python 3)、或者 UTF‑16 单元数(Java)。

· 反转、索引、子串操作必须考虑编码边界。

三、基本操作与复杂度

操作 典型实现复杂度 备注

拼接(concat) O(n + m) 不可变字符串会产生新对象,多次拼接用 StringBuilder

子串(substring) O(1) ~ O(k) Java 早期共享字符数组(可能内存泄漏),Go 重新分配

查找(indexOf) 朴素 O(n*m) 应使用 KMP / BM / 内置优化

替换(replace) O(n) 正则替换可能更慢

分割(split) O(n) 注意正则转义

四、匹配与搜索算法

算法 时间复杂度 场景

朴素匹配 O((n-m+1)*m) 小文本或教学

KMP O(n + m) 单模式、反复回退时(如流式匹配)

Boyer‑Moore 最好 O(n/m),最坏 O(n*m) 大文本、长模式,实际极快

Rabin‑Karp O(n + m),最坏 O(n*m) 多模式、滚动哈希

Aho‑Corasick O(n + Σ 所有模式总长) 同时匹配多个模式(敏感词过滤)

正则表达式 一般线性,但可能指数级回溯 匹配复杂模式,避免灾难性回溯

五、常见算法题型

5.1 双指针 / 滑动窗口

· 无重复最长子串

· 最小覆盖子串

· 字符串排列(异位词)

5.2 动态规划

· 最长公共子序列 (LCS)

· 编辑距离 (Levenshtein)

· 正则表达式匹配 (* 和 .)

· 交错字符串

5.3 回文

· 中心扩展法 O(n²)

· Manacher 算法 O(n) 求最长回文子串

5.4 前后缀 / 子序列

· KMP 的 next 数组应用(重复子串周期)

· 最短回文(在头部补字符)

· 判断子序列(可预处理下一字符位置)

5.5 字典树 (Trie)

· 前缀匹配、自动补全

· 单词搜索(二维网格)

· 最长公共前缀

5.6 后缀结构

· 后缀数组 + LCP 数组(用于重复子串、不同子串数)

· 后缀自动机 (SAM) 的 O(n) 构造

六、安全风险

漏洞类型 典型案例 防御措施

缓冲区溢出 C 的 gets()、strcpy() 未检查长度 使用 fgets()、strncpy() 或 C++ std::string

格式化字符串 printf(user_input) → 任意内存读写 固定格式:printf("%s", user_input)

SQL 注入 "SELECT * FROM users WHERE name = '" + name + "'" 参数化查询 / 转义

命令注入 system("ping " + ip) 使用 API 列表或严格过滤

正则拒绝服务 (ReDoS) (a+)+b 匹配 aaaaaaaaaaX 导致指数回溯 使用非回溯引擎、超时、避免嵌套量词

路径遍历 ../../etc/passwd 规范路径、白名单校验

七、不同语言的字符串特性速览

语言 不可变? 底层 性能注意点

Java 是(String) UTF‑16 数组 + coder 标识 拼接用 StringBuilder,substring 旧版可能持有大数组

Python 是 灵活表示(Latin1/UTF‑16/UTF‑32) 多次拼接用 join(),切片 O(k)

Go 否(底层只读视图) UTF‑8 字节数组,string 不可变 转换 []byte 复制,+ 拼接会重新分配

C++ 否(std::string 可变) 通常带 SSO c_str() 返回的指针在修改后失效

Rust 否(String 可变) UTF‑8,&str 为切片 索引需用 chars() 或 bytes(),避免按字节截断

八、优化技巧总结

· 预分配容量:已知最终长度时,用 reserve() 减少动态扩容。

· 避免重复转换:如循环内反复 toLowerCase() 或编码转换。

· 使用原始字符串:减少转义(如正则、路径)。

· 利用内存布局:连续数组上的 SIMD 指令可加速查找、比较(如 glibc 的 memcmp 用 SSE/AVX)。

· 字符串池(intern):相同内容的字符串复用对象(Java intern(),Python 自动对小字符串驻留)。

相关推荐
摇滚侠12 小时前
Java 饿汉式 单例模式
java·开发语言·单例模式
lbb 小魔仙12 小时前
工业数据困局的破局者:DolphinDB 如何让海量时序数据真正“跑“出价值
开发语言·人工智能·python·langchain
Devin~Y12 小时前
大厂Java面试实录:Spring Boot/WebFlux、JVM调优、Redis/Kafka、Spring Cloud 与 RAG/Agent 追问
java·jvm·spring boot·maven·mybatis·jpa·spring webflux
枫叶丹412 小时前
【HarmonyOS 6.0】Device Security Kit安全审计阻断功能深度解析
开发语言·安全·华为·harmonyos
读书札记202212 小时前
C++ switch..case语句中变量跨域问题探讨及解决方法
开发语言·c++
一轮弯弯的明月12 小时前
Spring AOP编程
java·开发语言·spring boot·笔记·spring aop·学习心得
qq_2965532712 小时前
矩阵逆时针旋转90度:三种解法从入门到精通
数据结构·python·算法·面试·矩阵
Sam_Deep_Thinking12 小时前
拼单功能的设计实战
java·架构
neo_Ggx2312 小时前
Linux 日志检索速查:按时间、接口、Trace ID 查询完整请求链路
java·linux·服务器
ch.ju12 小时前
Java程序设计(第3版)第四章——什么是对象
java·开发语言