字符串

字符串算法题目主要处理文本的查找、匹配、比较、变换和统计问题,其核心特点是输入数据为字符序列,解题关键在于利用其连续性、前缀性、字典序等特性,并常借助哈希、自动机、指针滑动、动态规划等技巧高效处理。


详细分类型与适用场景

当一道题的输入是一个或多个字符串时,你就应该考虑使用字符串算法。以下是主要的题目类型和适用场景:

1. 基础操作与模拟
  • 特点:直接考察对字符串的索引、遍历、拼接、反转等基本操作。

  • 常见题型:字符串反转、判断回文串、实现基本的字符串转换(如 atoi)、Z字形变换等。

  • 适用场景:问题描述本身就像是在指导你一步步操作字符串。

2. 匹配与查找问题

这是字符串问题的核心领域。

  • 特点:在一个主串(文本)中查找一个或多个模式串是否存在及出现的位置。

  • 常见算法

    • 暴力匹配:简单但低效,适用于小规模数据。

    • KMP算法:高效的单模式串匹配,利用“部分匹配表”避免回溯。

    • Rabin-Karp算法:利用滚动哈希进行多模式串匹配的预处理。

    • 字典树(Trie):快速检索字符串集合中是否存在某个前缀或整个字符串。

    • AC自动机字典树 + KMP 的思想,用于多模式串匹配的终极武器(如敏感词过滤)。

  • 适用场景:问题中出现“查找子串”、“所有出现位置”、“是否包含某些单词”等关键词。

3. 子串与子序列问题
  • 特点:不要求连续(子序列)或要求连续(子串)的序列问题,常求最大、最小、最长、最短等。

  • 常见题型

    • 最长回文子串:使用中心扩散法或Manacher算法。

    • 最长公共子串/子序列(LCS):经典动态规划问题。

    • 最长不含重复字符的子串:使用滑动窗口(双指针)的代表性问题。

    • 最短编辑距离:另一个经典的动态规划问题,衡量两个字符串的相似度。

  • 适用场景:问题要求找到一个满足特定条件的“序列”,且这个序列源自原字符串。

4. 计数与统计问题
  • 特点:统计字符串中字符、子串、模式出现的频率、数量或分布。

  • 常见题型:统计字母出现次数、统计“优美子串”的数目、不同子串的个数等。

  • 适用场景:问题中出现“有多少种”、“出现次数”、“频率最高”等统计性词汇。常结合哈希表来记录频率。

5. 分割与组合问题
  • 特点:将字符串按一定规则进行分割,或者由多个部分组合成一个新字符串。

  • 常见题型:单词拆分、回文分割、恢复IP地址等。

  • 适用场景:问题要求将字符串切割成若干段,每段需要满足特定条件。这类问题通常使用回溯法(DFS) 或动态规划来解决。

6. 表达式 parsing 与计算
  • 特点:处理具有特定语法结构的字符串,如数学表达式、JSON、XML等。

  • 常见题型:基本计算器(实现加减乘除括号)、逆波兰表达式求值、解析HTML标签等。

  • 适用场景:输入字符串具有明确的递归或嵌套结构。解决方案通常是使用递归下降等解析方法。

7. 字符串排序与字典序问题
  • 特点:利用字符串的字典序特性进行排序或比较。

  • 常见题型:拼接所有字符串使字典序最小、最长快乐前缀、后缀数组等。

  • 适用场景:问题要求比较字符串的“大小”或按特定顺序排列字符串。

总结

当你看到问题的输入是字符串,并且问题目标涉及查找、匹配、比较、变换、计数、分割这几种操作时,它就是一个字符串算法题。解决它们的关键是选择合适的数据结构(哈希表、Trie、栈)和算法思想(滑动窗口、动态规划、回溯、自动机)。

题目练习

14. 最长公共前缀 - 力扣(LeetCode)

解法:

算法思路:

解法一(两两比较):

我们可以先找出前两个的最长公共前缀,然后拿这个最长公共前缀依次与后面的字符串比较,这样就可以找出所有字符串的最长公共前缀

class Solution {
public:string longestCommonPrefix(vector<string>& strs) {string ret = strs[0];for(int i = 1; i < strs.size(); ++i)ret = findCommon(ret, strs[i]);return ret;}string findCommon(string& s1, string& s2){int i = 0;while(i < min(s1.size(), s2.size()) && s1[i] == s2[i]) ++i;return s1.substr(0, i);}
};

解法二(统一比较):

题目要求多个字符串的公共前缀,我们可以逐位比较这些字符串,哪一位出现了不同,就在哪一位截止

class Solution {
public:string longestCommonPrefix(vector<string>& strs) {for(int i = 0; i < strs[0].size(); ++i){char tmp = strs[0][i];for(int j = 1; j < strs.size(); ++j){if(i == strs[j].size() || tmp != strs[j][i]) return strs[0].substr(0, i);}}return strs[0];}
};

5. 最长回文子串 - 力扣(LeetCode)

解法(中心扩散):

算法思路:

枚举每一个可能的子串非常费时,有没有比较简单一点的方法呢?

对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。如此这样去除,一直除到长度小于等于 2 时呢?长度为 1 的,自身与自身就构成回文;而长度为 2 的,就要判断这两个字符是否相等了。

从这个性质可以反推出来,从回文串的中心开始,往左读和往右读也是一样的那么,是否可以枚举回文串的中心呢?

从中心向两边扩展,如果两边的字母相同,我们就可以继续扩展;如果不同,我们就停止扩展。这样只需要一层 for 循环,我们就可以完成先前两层 for 循环的工作量。

class Solution {
public:string longestPalindrome(string s) {int begin = 0, len = 0, n = s.size();for(int i = 0; i < n; ++i){int left = i, right = i;while(left >= 0 && right < n && s[left] == s[right]){left--;right++;}if(right - left - 1 > len){begin = left + 1;len = right - left - 1;}left = i, right = i + 1;while(left >= 0 && right < n && s[left] == s[right]){left--;right++;}if(right - left - 1 > len){begin = left + 1;len = right - left - 1;}}return s.substr(begin, len);}
};

67. 二进制求和 - 力扣(LeetCode)

解法(模拟十进制的大数相加的过程):

算法思路:

模拟十进制中我们列竖式计算两个数之和的过程。但是这里是二进制的求和,我们不是逢十进一,而是逢二进一

class Solution {
public:string addBinary(string a, string b) {string ret;int cur1 = a.size() - 1, cur2 = b.size() - 1, t = 0;while(cur1 >= 0 || cur2 >= 0 || t){if(cur1 >= 0) t += a[cur1--] - '0';if(cur2 >= 0) t += b[cur2--] - '0';ret += t % 2 + '0';t /= 2;}reverse(ret.begin(), ret.end());return ret;}
};

43. 字符串相乘 - 力扣(LeetCode)

解法(无进位相乘然后相加,最后处理进位):

算法思路:

整体思路就是模拟我们小学列竖式计算两个数相乘的过程。但是为了我们书写代码的方便性,我们选择一种优化版本的,就是在计算两数相乘的时候,先不考虑进位,等到所有结果计算完毕之后,再去考虑进位。如下图:

class Solution {
public:string multiply(string num1, string num2) {int m = num1.size(), n = num2.size();reverse(num1.begin(), num1.end());reverse(num2.begin(), num2.end());vector<int> tmp(m + n - 1);for(int i = 0; i < m; ++i){for(int j = 0; j < n; ++j){tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');}}int cur = 0, t = 0;string ret;while(cur < m + n - 1 || t){if(cur < m + n - 1) t += tmp[cur++];ret += t % 10 + '0';t /= 10;}while(ret.size() > 1 && ret.back() == '0') ret.pop_back();reverse(ret.begin(), ret.end());return ret;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/100393.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/100393.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/100393.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot中 Gzip 压缩的两种开启方式:GeoJSON 瘦身实战

目录 前言 一、GZIP压缩知识简介 1、什么是Gzip 2、Gzip特点 3、Gzip在GIS方面的应用 二、SpringBoot中开启Gzip的方式 1、在SpringBoot中开启Gzip的知识简介 2、SpringBoot中GeoJSON的实例 三、全局开启Gzip实现 1、实现原理 2、实现效果 四、局部约定配置 1、实现…

PPTist+cpolar:开源演示文稿的远程创作方案

文章目录前言【视频教程】1. 本地安装PPTist2. PPTist 使用介绍3. 安装Cpolar内网穿透4. 配置公网地址6. 配置固定公网地址前言 PPTist作为开源在线演示文稿工具&#xff0c;提供媲美PowerPoint的核心功能&#xff0c;支持多页面编辑、图表插入、音视频嵌入和动画效果设置。特…

服务注册/服务发现-Eureka

目的&#xff1a;解决微服务在调用远程服务时URL写死的问题注册中心服务提供者&#xff08;Server&#xff09;&#xff1a;一次业务中&#xff0c;被其他微服务调用的服务&#xff0c;也就是提供接口给其他微服务。服务消费者&#xff08;Client&#xff09;:一次业务中&#…

cuda stream

基本概念 cuda stream表示GPU的一个操作队列&#xff0c;操作在队列中按照一定的顺序执行&#xff0c;也可以向流中添加一定的操作如核函数的启动、内存的复制、事件的启动和结束等 一个流中的不同操作有着严格的顺序&#xff0c;但是不同流之间没有任何限制 cuda stream中排队…

数据结构:完全二叉树

完全二叉树 定义&#xff1a; 按层序遍历&#xff08;从上到下&#xff0c;从左到右&#xff09;填充节点。 除了最后一层外&#xff0c;其余各层必须全满。 最后一层的节点必须 连续靠左。 完全二叉树不一定是满二叉树。 满二叉树 (Full Binary Tree)&#xff1a;每个节点都有…

【Java初学基础】⭐Object()顶级父类与它的重要方法equals()

object类常见方法/*** native 方法&#xff0c;用于返回当前运行时对象的 Class 对象&#xff0c;使用了 final 关键字修饰&#xff0c;故不允许子类重写。*/ public final native Class<?> getClass() /*** native 方法&#xff0c;用于返回对象的哈希码&#xff0c;主…

用深度学习(LSTM)实现时间序列预测:从数据到闭环预测全解析

用深度学习&#xff08;LSTM&#xff09;实现时间序列预测&#xff1a;从数据到闭环预测全解析 时间序列预测是工业、金融、环境等领域的核心需求——小到预测设备温度波动&#xff0c;大到预测股价走势&#xff0c;都需要从历史数据中挖掘时序规律。长短期记忆网络&#xff08…

gpu-z功能介绍,安装与使用方法

GPU-Z 功能介绍、安装与使用方法 一、核心功能 硬件信息检测 识别显卡型号、制造商、核心架构&#xff08;如NVIDIA Ada Lovelace、AMD RDNA 3&#xff09;、制造工艺&#xff08;如5nm、7nm&#xff09;。显示显存类型&#xff08;GDDR6X、HBM2e&#xff09;、容量、带宽及显…

数据搬家后如何处理旧 iPhone

每年&#xff0c;苹果都会推出新款 iPhone&#xff0c;激发了人们升级到 iPhone 17、iPhone 17 Pro、iPhone 17 Pro Max 或 iPhone Air 等新机型的热情。但在获得新 iPhone 之前&#xff0c;有一件重要的事情要做&#xff1a;将数据从旧 iPhone 转移到新设备。虽然许多用户都能…

Java关键字深度解析(上)

这是一份全面的Java关键字实战指南 目录 1.数据类型关键字:内存布局与性能优化 1.1 基础类型的内存密码 byte-内存的极简主义者 int-Java世界的万能钥匙 long - 时间与ID的守护者 1.2 引用类型的架构设计 String-不是关键字但胜于关键字 2.访问修饰符:企业级权限控制 …

C语言深度解析:指针数组与数组指针的区别与应用

目录 1 引言&#xff1a;从名字理解本质区别 2 指针数组&#xff1a;灵活管理多个指针 2.1 基本概念与声明方式 2.2 内存布局与特性 2.3 典型应用场景&#xff1a;字符串数组与多维度数据管理 2.3.1 静态分配示例&#xff1a;字符串数组 2.3.2 动态分配示例&#xff1a;…

Node.js 高级应用:负载均衡与流量限制

在当今高并发的网络应用环境中&#xff0c;如何有效地分配服务器资源并保护系统免受恶意攻击是开发者必须面对的重要问题。Node.js 作为一款广受欢迎的服务器端 JavaScript 运行时环境&#xff0c;提供了丰富的工具和模块来应对这些挑战。本文将深入探讨如何在 Node.js 中实现负…

信任链验证流程

信任链验证流程 (The Chain of Trust)整个过程就像一场严格的接力赛&#xff0c;每一棒都必须从可信的上一位手中接过接力棒&#xff08;信任&#xff09;&#xff0c;验证无误后&#xff0c;再跑自己的那段路&#xff0c;并把信任传递给下一棒现在&#xff0c;我们来详细解读图…

黄昏时刻复古胶片风格人像风光摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程这套 黄昏时刻复古胶片风格人像风光摄影后期 Lr 调色方案&#xff0c;以落日余晖为核心色彩元素&#xff0c;加入复古胶片质感&#xff0c;让画面充满温暖与怀旧氛围。整体色调偏向橙红与青绿的互补对比&#xff0c;天空的夕阳光影与人像肤色相互映衬&#xff0c;既有胶…

硬件驱动——I.MX6ULL裸机启动(3)(按键设置及中断设置

重点&#xff1a;1.GIC&#xff1a;&#xff08;Generic Interrupt Controller&#xff09;通用中断控制器&#xff0c;是ARM架构中用于管理中断的核心模块&#xff0c;主要用于现代多核处理器系统。它负责接收&#xff0c;分发并分发中断请求&#xff0c;减轻CPU负担&#x…

用deepseek对GPU服务器进行压力测试

利用 DeepSeek 模型对 GPU 服务器进行压力测试&#xff0c;核心思路是通过模拟高负载的模型推理 / 微调任务&#xff0c;验证 GPU 服务器在计算、显存、网络等维度的承载能力&#xff0c;同时观察稳定性与性能瓶颈。以下是具体的测试方案&#xff0c;涵盖测试环境准备、核心测试…

ARM(7)IMX6ULL 按键控制(轮询 + 中断)优化工程

一、硬件介绍1. 开关功能定义共 3 个开关&#xff08;两红一黄&#xff09;&#xff0c;功能分工明确&#xff1a;中间开关&#xff1a;复位按钮左边开关&#xff1a;低功耗按钮右边开关&#xff1a;用户独立控制的试验按键&#xff08;核心控制对象&#xff09;2. 核心电平逻辑…

【QT随笔】什么是Qt元对象系统?Qt元对象系统的核心机制与应用实践

【QT随笔】什么是Qt元对象系统&#xff1f;Qt元对象系统的核心机制与应用实践 之所以写下这篇文章&#xff0c;是因为前段时间自己面试的时候被问到了&#xff01;因此想借此分享一波&#xff01;&#xff01;&#xff01;本文主要详细解释Qt元对象系统的概念、作用及实现机制…

从技术视角解析加密货币/虚拟货币/稳定币的设计与演进

随着加密货币行情的持续走高&#xff0c;除了资产价值&#xff0c;我想试着从底层程序设计与架构角度解析比特币、以太坊、稳定币以及新兴公链的核心技术方案。作者在2018年设计实施了基于区块链技术的金融项目&#xff0c;并荣获了国家课题进步奖&#xff0c;对加密货币及场景…

[MySQL]Order By:排序的艺术

[MySQL]Order By&#xff1a;排序的艺术 1. 简介 在数据库管理中&#xff0c;数据的排序是一项至关重要的操作。MySQL 的 ORDER BY 子句为我们提供了强大而灵活的功能&#xff0c;用于对查询结果进行排序。无论是按照字母顺序排列名称&#xff0c;还是根据日期或数值进行升序…