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 自动对小字符串驻留)。

相关推荐
梦想的颜色2 小时前
java 利用redis来限制用户频繁点击
java·开发语言
报错小能手2 小时前
Swift 并发 Combine响应式框架
开发语言·ios·swift
念越2 小时前
算法每日一题 Day08|双指针法解决三数之和
算法·力扣
万法若空2 小时前
C++ <memory> 库全方位详解
开发语言·c++
黎阳之光2 小时前
黎阳之光透明管理:视频孪生重构智慧仓储新范式
人工智能·算法·安全·重构·数字孪生
代码中介商2 小时前
C++ 类型转换深度解析:static_cast、dynamic_cast、const_cast、reinterpret_cast
开发语言·c++
青小莫2 小时前
C++之string(OJ练习)
开发语言·c++·stl
freshman_y2 小时前
一篇介绍C语言中二级指针和二维数组的文章
c语言·开发语言
-Marks-2 小时前
【C++编程】STL简介 --- (是什么 | 版本发展历程 | 六大组件 | 重要性缺陷以及如何学习)
开发语言·c++·学习·stl·stl版本