剑指Offer(数据结构与算法面试题精讲)C++版——day6
剑指Offer(数据结构与算法面试题精讲)C++版——day6
- 题目一:不含重复字符的最长子字符串
- 题目二:包含所有字符的最短字符串
- 题目三:有效的回文
题目一:不含重复字符的最长子字符串

这里还是可以使用前面,提到的双指针方法,使用左右两个指针定界(不妨记为front和end指针),一开始front指针和end指针都指向第一个字符,显然没有出现重复字符,然后end指针后移,计算这里front指针和end指针之间的子串是否存在重复字符,如果存在重复字符,那么将front前移,重新计算统计是否重复。比如这里的示例,等到front和end指针之间为“bab”时发现重复,于是front前移,front和end之间的子串调整为“ab”,再次检测是否具备重复的字符。由于这里没有强调使用的字符集范围,这里取常用ASCII码作为字符集,这样就能够使用hash表来存储每个字符出现的次数,实现快速存取,于是得到如下代码:
# include <iostream>
# include <algorithm>
using namespace std;
bool isAllOnce(int count[]) {for(int i=0; i<256; ++i) {if(count[i]==2)return false;}return true;
}
int maxSubStrLength(string str) {int i=0,j=0,maxLength=1,len=str.length();int count[256]= {0};for(j=0; j<len; ++j) {count[str[j]]++;if(!isAllOnce(count)) {count[str[i]]--;i++;} else {if(j-i+1>maxLength) {maxLength=j-i+1;}}}return maxLength;
}
int main() {string s1="babcca";cout<<"输出最大不重复子串的长度:"<<maxSubStrLength(s1)<<endl;return 0;
}

接下来对上述代码的时间复杂度进行深入分析。在该算法的实现过程中,其中使用的 hash 表被设定大小为 256 。之所以这样设置,是因为它能够较为全面地涵盖可能出现的字符情况。当对这个 hash 表进行扫描操作时,由于其固定大小为 256 ,所以需要进行 256 次判断操作。从算法时间复杂度的概念来讲,尽管存在这 256 次的判断,但由于这个操作次数是一个固定的常量,与输入数据的规模大小并无关联,所以这部分操作的时间复杂度依然属于 O(1) 级别。在此基础上,我们转换视角,站在变量 i ,也就是可以理解为 front 指针的角度来进一步考量。因为在整个算法流程中, front 指针最多只需要从数组的起始位置一直扫描到数组的末尾位置,即最多需要完整地扫描整个数组一次。而数组的长度是由输入数据的规模 n 所决定的,随着 n 的变化, front 指针扫描数组的操作次数也会相应变化,且呈线性关系。综合以上两部分的分析,整体算法最终的时间复杂度也就确定为 O(n) 。
题目二:包含所有字符的最短字符串

这里依旧可以考虑使用hash表和双指针的方式来统计是否存在这样的数组。思路大致为,首先扫描一次字符串t,然后标记其中每个字符出现的次数,然后使用双指针遍历s字符串,如果出现了一个子串,使得包含了t中的所有字符,那么统计这个子串和子串的长度,这样便能够遍历完所有子串,每次找到子串之后都更新成最短的那个子串,最终得到如下代码:
# include <iostream>
# include <algorithm>
using namespace std;void initCountNum(string t,int count[]) {for(int i=0; i<256; ++i) {count[i]=0;}for(int i=0,len=t.length(); i<len; ++i) {count[t[i]]++;}
}
bool isEmpty(int count[]) {for(int i=0; i<256; ++i) {if(count[i]>0)return false;}return true;
}
string getMinLenStr(string s,string t) {int count[256]= {0},len1=s.length(),len2=t.length();int i=0,j=len2-1,strLen=-1;string result="";while(j<len1&&i<len1-len2) {initCountNum(t,count);for(int k=i; k<=j; ++k) {count[s[k]]--;}if(isEmpty(count)) {if(j-i+1<strLen||strLen==-1) {strLen=j-i+1;result=s.substr(i,strLen);}i++;} else {j++;}}return result;
}
int main() {string s="ADDBANCAD";string t="ABC";cout<<"输出s中包含t字符的最短子串:"<<getMinLenStr(s,t)<<endl;return 0;
}

这里的时间复杂度应该怎么分析呢?对于这里函数涉及比较多的算法,分析时间复杂度可以按照函数进行拆解,这里不妨假设字符串s和字符串t的长度分别为m和n,同上面的分析,对于算法isEmpty都是循环并判断256次,这里的时间复杂度为O(1),对于算法initCountNum时间复杂度为O(m)。接下来,算法的时间复杂度应该着重分析getMinLenStr函数,在双指针遍历时,最坏的情况下,第一次遍历到了最后一个字符才拿到了满足要求的子串,需要遍历n-m次,接下来为了尽可能缩短子串长度,因此左指针右移,这部分还需要的比较次数为n-m次,但由于每次需要初始化计数数组count并且需要扣减计数,因此总时间复杂度为O((m+n)*n)。
题目三:有效的回文

回文字符串相关的问题是十分经典且常见的类型,不仅在日常的算法学习和练习中频繁出现,在 LeetCode 上也经常出现。本题的特殊之处在于,题目明确限定了只需要考虑字符串中的字母和数字字符,这一条件为我们的解题思路奠定了基础。基于此,我们的第一步操作便是对原始字符串进行全面且细致的清洗工作。在清洗过程中,需要逐个字符地进行排查,精准地筛选出其中所有的字母和数字字符。同时,对于字母字符里的大写字母,为了保证后续处理的一致性和便捷性,要将其一一转换成对应的小写字母。当完成了字符串的清洗步骤后,就该运用到双指针这一巧妙的算法技巧了。我们设定两个指针,一个处于字符串的最左端,另一个位于字符串的最右端,随后让这两个指针同时朝着字符串的中间方向移动遍历。在遍历的每一个过程中,都要对两个指针所指向的字符内容进行严格比较。一旦发现两个指针指向的内容存在不一致的情况,那么就可以迅速判定这个字符串并非回文串。通过这样严谨且有序的操作流程,我们最终能够实现对回文字符串的准确判断,于是也就得到了如下的代码:
# include <iostream>
# include <algorithm>
using namespace std;bool isPalindrome(string s) {int len=s.length();for(int i=0,j=len-1; i<len/2; ++i,--j) {if(s[i]!=s[j])return false;}return true;
}
string filterStr(string s) {string result="";for(int i=0,len=s.length(); i<len; ++i) {if((s[i]>='a'&&s[i]<='z')||(s[i]>='0'&&s[i]<='9')) {result+=s[i];} else if(s[i]>='A'&&s[i]<='Z') {result+=tolower(static_cast<unsigned char>(s[i]));}}return result;
}
int main() {string s="Was it a cat I saw";cout<<"判断是否是回文字符串:"<<isPalindrome(filterStr(s))<<endl;return 0;
}

这里我们需要积累一下,C++下大小写的转换方法,之后字符串系列算法估计还会用到。
我是【Jerry说前后端】,本系列精心挑选的算法题目全部基于经典的《剑指 Offer(数据结构与算法面试题精讲)》。在如今竞争激烈的技术求职环境下,算法能力已成为前端开发岗位笔试考核的关键要点。通过深入钻研这一系列算法题,大家能够系统地积累算法知识和解题经验。每一道题目的分析与解答过程,都像是一把钥匙,为大家打开一扇通往高效编程思维的大门,帮助大家逐步提升自己在数据结构运用、算法设计与优化等方面的能力。
无论是即将踏入职场的应届毕业生,还是想要进一步提升自己技术水平的在职开发者,掌握扎实的算法知识都是提升竞争力的有力武器。希望大家能跟随我的步伐,在这个系列中不断学习、不断进步,为即将到来的前端笔试做好充分准备,顺利拿下心仪的工作机会!快来订阅吧,让我们一起开启这段算法学习之旅!
相关文章:
剑指Offer(数据结构与算法面试题精讲)C++版——day6
剑指Offer(数据结构与算法面试题精讲)C版——day6 题目一:不含重复字符的最长子字符串题目二:包含所有字符的最短字符串题目三:有效的回文 题目一:不含重复字符的最长子字符串 这里还是可以使用前面&#x…...
freertos韦东山---事件组以及实验
事件组的原理是什么,有哪些优点,为啥要创造出这个概念 在实时操作系统(如 FreeRTOS)中,事件组是一种用于任务间同步和通信的机制,它的原理、优点及存在意义如下: 事件组原理 数据结构…...
架构师面试(二十六):系统拆分
问题 今天我们聊电商系统实际业务场景的问题,考查对业务系统问题的分析能力、解决问题的能力和对系统长期发展的整体规划能力。 一电商平台在早期阶段业务发展迅速,DAU在 10W;整个电商系统按水平分层架构进行设计,包括【入口网关…...
Spring 中的事务
🧾 一、什么是事务? 🧠 通俗理解: 事务 一组操作,要么全部成功,要么全部失败,不能只做一半。 比如你转账: A 账户扣钱B 账户加钱 如果 A 扣了钱但 B 没收到,那就出问…...
Java中的同步和异步
一、前言 在Java中,同步(Synchronous)和异步(Asynchronous)是两种不同的任务处理模式。核心区别在任务执行的顺序控制和线程阻塞行为。 二、同步(Synchronous) 定义:任务按顺序执行…...
vue2 vue3 响应式差异
vue2 响应式原理看这 链接: link 总结: object.defineproperty()是对属性的劫持,对属性劫持有两大缺陷 1. 需要遍历对象的所有属性,深层属性需递归,存在效率问题 2. 后添加的属性,无法获得响应式,因为劫持…...
唯一ID生成器设计方案
《亿级流量系统架构设计与实战》总结 1. 唯一ID的核心需求 • 全局唯一性:分布式系统中所有节点生成的ID不可重复。 • 趋势递增性(可选):ID按时间或序列递增,优化数据库写入性能。 • 高可用性:服务需72…...
OpenCV 图形API(16)将极坐标(magnitude 和 angle)转换为笛卡尔坐标(x 和 y)函数polarToCart()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 描述 计算二维向量的 x 和 y 坐标。 polarToCart 函数根据 magnitude 和 angle 的对应元素表示的每个二维向量,计算其笛卡尔坐标:…...
在 Ubuntu24.04 LTS 上 Docker Compose 部署基于 Dify 重构二开的开源项目 Dify-Plus
一、安装环境信息说明 硬件资源(GB 和 GiB 的主要区别在于它们的换算基数不同,GB 使用十进制,GiB 使用二进制,导致相同数值下 GiB 表示的容量略大于 GB;换算关系:1 GiB ≈ 1.07374 GB ;1 GB ≈ …...
安装和配置Docker
其他版本的安装方式可直接参考官方网站,推荐通过官方网站提供的方式安装Dockers,下面只是个演示的示例,仅供参考 Install | Docker Docs 安装 Docker 的前置准备 1.虚拟机配置: 推荐配置 内存:4GB(最低…...
Ansible YAML 基础语法与关键词 的详细指南
以下是 Ansible YAML 基础语法与关键词 的详细指南,帮助你快速掌握 Playbook 编写规范和核心概念: 目录 一、Ansible Playbook 基础结构1. YAML 文件基础 二、核心关键词1. Play 定义2. Task 定义3. Handler 定义4. 变量(Variables࿰…...
NO.64十六届蓝桥杯备战|基础算法-简单贪心|货仓选址|最大子段和|纪念品分组|排座椅|矩阵消除(C++)
贪⼼算法是两极分化很严重的算法。简单的问题会让你觉得理所应当,难⼀点的问题会让你怀疑⼈⽣ 什么是贪⼼算法? 贪⼼算法,或者说是贪⼼策略:企图⽤局部最优找出全局最优。 把解决问题的过程分成若⼲步;解决每⼀步时…...
瑞萨RA4M2使用心得-KEIL5的第一次编译
目录 前言 环境: 开发板:RA-Eco-RA4M2-100PIN-V1.0 IDE:keil5.35 一、软件的下载 编辑瑞萨的芯片,除了keil5 外还需要一个软件:RASC 路径:Releases renesas/fsp (github.com) 向下找到: …...
java根据集合中对象的属性值大小生成排名
1:根据对象属性降序排列 public static <T extends Comparable<? super T>> LinkedHashMap<T, Integer> calculateRanking(List<ProductPerformanceInfoVO> dataList, Function<ProductPerformanceInfoVO, T> keyExtractor) {Linked…...
数据分析-Excel-学习笔记
Day1 复现报表聚合函数:日期联动快速定位区域SUMIF函数SUMIFS函数环比、同比计算IFERROR函数混合引用单元格格式总结汇报 拿到一个Excel表格,首先要看这个表格个构成(包含了哪些数据),几行几列,每一列的名称…...
整车CAN网络和CANoe
车载网络中主要包含有Can网络,Lin网络,FlexRay,Most,以太网。 500kbps:500波特率,表示的数据传输的速度。表示的是最大的网速传输速度。也就是每秒 500kb BodyCan车身Can InfoCan娱乐信息Can 车身CAN主要连接的是ESB电动安全带 ADB自适应远光灯等 PTCan动力Can 底盘Can...
ChatGPT 的新图像生成器非常擅长伪造收据
本月,ChatGPT 推出了一种新的图像生成器,作为其 4o 模型的一部分,该模型在生成图像内的文本方面做得更好。 人们已经在利用它来生成假的餐厅收据,这可能会为欺诈者使用的已经很广泛的 AI 深度伪造工具包添加另一种工具。 多产的…...
JS页面尺寸事件
元素位置 在这里插入图片描述 父元素带有定位时输出相对于父亲元素的距离值...
SpringBoot的日志框架
目录 默认日志框架 日志配置 更换日志框架 排除默认Logback 引入目标日志框架 添加配置文件 logback.xml SpringBoot的核心设计宗旨是约定大于配置,很多框架功能都给你默认加载和配置完成供你使用,但这就要求使用者对框架有一定的理解和改造能力,比如这个日志框架,是其…...
网络协议之基础介绍
写在前面 本文看下网络协议相关基础内容。 1:为什么要有网络协议 为了实现世界各地的不同主机的互联互通。 2:协议的三要素 协议存在的目的就是立规矩,无规矩不成方圆嘛!但是这个规矩也不是想怎么立就怎么立的,也…...
【学Rust写CAD】34 精确 Alpha 混合函数(argb.rs补充方法)
源码 #[inline]pub fn over_exact(self, dst: Argb) -> Argb {let a 255 - self.alpha32();let t dst.rb() * a 0x80_00_80;let mut rb (t ((t >> 8) & Argb::MASK)) >> 8;rb & Argb::MASK;rb self.rb();// saturaterb | 0x1000100 - ((rb >&…...
利用NumPy核心知识点优化TensorFlow模型训练过程
利用NumPy核心知识点优化TensorFlow模型训练过程 NumPy是Python科学计算的基础库,掌握它的高效操作可以显著提升TensorFlow模型的训练效率。本文详细探讨如何将NumPy的核心优势应用于TensorFlow模型训练的各个环节。 1. 数据预处理优化 高效向量化操作 NumPy的向…...
初识数据结构——Java集合框架解析:List与ArrayList的完美结合
📚 Java集合框架解析:List与ArrayList的完美结合 🌟 前言:为什么我们需要List和ArrayList? 在日常开发中,我们经常需要处理一组数据。想象一下,如果你要管理一个班级的学生名单,或…...
TDengine 从入门到精通(2万字长文)
目录 第一章:走进 TDengine 的世界 TDengine 是个啥? TDengine 的硬核特性 性能炸裂 分布式架构,天生可扩展 SQL 用起来贼顺手 写入方式花样多 内置缓存,省心又省力 TDengine 能干啥? 智能制造 能源管理 物联网平台 工业大数据 第二章:上手 TDengine:安装与…...
DevOps 与持续集成(CI/CD)
1. DevOps 概述 DevOps(Development + Operations)是一种软件开发方法,强调开发(Dev)与运维(Ops)协作,通过自动化工具提高软件交付效率。其目标是: ✅ 提高部署速度 —— 频繁发布新版本 ✅ 减少人为错误 —— 通过自动化降低运维风险 ✅ 增强可观测性 —— 监控和日…...
[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
在 Web 应用中,处理表格数据并提供 Excel 级的功能(如公式计算、数据导入导出)一直是个挑战。今天,我将带你使用 React Handsontable 搭建一个强大的 Excel 风格表格,支持 公式计算、Excel 文件导入导出,并…...
uniapp微信小程序引入vant组件库
1、首先要有uniapp项目,根据vant官方文档使用yarn或npm安装依赖: 1、 yarn init 或 npm init2、 # 通过 npm 安装npm i vant/weapp -S --production# 通过 yarn 安装yarn add vant/weapp --production# 安装 0.x 版本npm i vant-weapp -S --production …...
贪心进阶学习笔记
反悔贪心 贪心是指直接选择局部最优解,不需要考虑之后的影响。 而反悔贪心是在贪心上面加了一个“反悔”的操作,于是又可以撤销之前的“鲁莽行动”,让整个的选择稍微变得“理智一些”。 于是,我个人理解,反悔贪心是…...
Java 大视界 -- Java 大数据在航天遥测数据分析中的技术突破与应用(177)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
架构师面试(二十七):单链表
问题 今天的问题对于架构师来说会相对容易许多。今天出一个【数据结构与算法】相关的题目,醒醒脑。 给一张【单链表】,该单链表有100个节点元素(当然,事先我们是不知道100这个数目的),要获取倒数第8个元素…...
