【每日一题】LeetCode - 最长公共前缀

【每日一题】LeetCode - 最长公共前缀

给定一个字符串数组 strs,寻找它们的最长公共前缀。如果不存在公共前缀,则返回空字符串 ""

示例

示例 1
输入: strs = ["flower","flow","flight"]
输出: "fl"

示例 2
输入: strs = ["dog","racecar","car"]
输出: ""
解释:字符串数组中没有共同前缀,因此返回空字符串。

限制条件

  • 数组长度 1 <= strs.length <= 200
  • 字符串长度 0 <= strs[i].length <= 200
  • 所有字符串均为小写英文字母

2. 解题思路与实现方法

方法 1:横向扫描法

将第一个字符串作为初始公共前缀,逐一与数组中的其他字符串对比,通过缩减前缀长度来保证公共性。最终得到的是所有字符串的最长公共前缀。

代码实现
#include<iostream>#include<vector>#include<string>#include<algorithm>usingnamespace std;classSolution{public: string longestCommonPrefix(vector<string>& strs){ string prefix = strs[0];// 初始前缀for(int i =1; i < strs.size();++i){int j =0;// 比较前缀与当前字符串的公共部分while(j < prefix.size()&& j < strs[i].size()&& prefix[j]== strs[i][j]){++j;} prefix = prefix.substr(0, j);// 更新前缀长度if(prefix.empty())break;// 若前缀为空,直接返回}return prefix;}};intmain(){ Solution s; vector<string> strs ={"flower","flow","flight"}; cout << s.longestCommonPrefix(strs)<< endl;return0;}
代码解析
  1. 初始设置:将 strs[0] 作为初始公共前缀 prefix
  2. 逐个比较:遍历剩余的字符串,每次更新 prefix 为其与当前字符串的公共前缀。
  3. 返回结果:当 prefix 缩减为 0 时,立即返回空字符串;否则返回最终公共前缀。
时间复杂度计算
  • 最坏情况:所有字符串长度相等且无公共前缀时,时间复杂度为 O(S),其中 S 是数组中所有字符的总和。
  • 平均情况:由于每次比较时前缀逐渐缩短,通常能达到 O(minLen * n) 的效率,minLen 为字符串中最小长度,n 为字符串个数。
空间复杂度

仅使用常数额外空间,空间复杂度为 O(1)


方法 2:动态规划

此问题可转化为动态规划问题,逐字符检查公共前缀的长度。

  1. 状态定义:定义 dp[i][j] 表示到第 i 个字符串和第 j 个字符时的最长公共前缀长度。
  2. 状态转移方程:如果 strs[i][j] == strs[i-1][j],则 dp[i][j] = dp[i-1][j] + 1,否则 dp[i][j] = 0
  3. 初始条件:第一个字符串为初始公共前缀,依次向后遍历更新。
代码实现
#include<iostream>#include<vector>#include<string>usingnamespace std;classSolution{public: string longestCommonPrefix(vector<string>& strs){if(strs.empty())return"";int n = strs.size();int minLen = INT_MAX;// 寻找最小字符串长度for(const string& s : strs){ minLen =min(minLen,(int)s.length());}int low =1, high = minLen;while(low <= high){int mid =(low + high)/2;if(isCommonPrefix(strs, mid)) low = mid +1;else high = mid -1;}return strs[0].substr(0,(low + high)/2);}private:boolisCommonPrefix(const vector<string>& strs,int len){ string prefix = strs[0].substr(0, len);for(int i =1; i < strs.size(); i++){if(strs[i].find(prefix)!=0){returnfalse;}}returntrue;}};intmain(){ Solution solution; vector<string> strs ={"flower","flow","flight"}; cout << solution.longestCommonPrefix(strs)<< endl;return0;}
代码解析
  1. 初始化:找到最短字符串的长度,设为 minLen
  2. 二分搜索:通过二分法逐步缩小范围,判断当前长度是否是公共前缀。
  3. 判断公共前缀:利用 isCommonPrefix 函数检查当前长度 len 是否为公共前缀。
  4. 返回结果:最终获得的 (low + high) / 2 即最长公共前缀长度。
时间复杂度分析
  • 二分查找的复杂度为 O(log minLen),每次查找调用 isCommonPrefix 的时间复杂度为 O(n * minLen)。因此总复杂度为 O(n * minLen * log minLen)
  • 空间复杂度为 O(1)

方法 3:纵向扫描法

逐列检查每个字符是否相同,遇到不同则停止。这种方法直观易懂,适用于小规模字符串数组。

代码实现
string longestCommonPrefix(vector<string>& strs){if(strs.empty())return"";for(int i =0; i < strs[0].size(); i++){char c = strs[0][i];for(int j =1; j < strs.size(); j++){if(i == strs[j].size()|| strs[j][i]!= c){return strs[0].substr(0, i);}}}return strs[0];}

3. 方法对比与总结

方法时间复杂度空间复杂度适用场景
横向扫描法O(S)O(1)字符串较多
二分法+动态规划O(n * minLen * log minLen)O(1)大规模字符串
纵向扫描法O(S)O(1)小规模字符串
  • 横向扫描法纵向扫描法都适合中小规模数据,横向法代码更简洁。
  • 二分法结合动态规划提升了效率,适用于需要更高效率的情况。

Read more

【C++ 内存申请】从 C++ new 到内核:虚拟内存、VMA 与内存泄漏的全链路解析

【C++ 内存申请】从 C++ new 到内核:虚拟内存、VMA 与内存泄漏的全链路解析

目录标题 * 1. 从 C++ `new` 到物理内存:堆、虚拟内存和 VMA 究竟发生了什么 * 1.1 C++ 视角:`new` / `malloc` 并不等于系统调用 * 1.2 OS 视角:VMA、页表和按需分配(demand paging) * 1.3 硬件视角:第一次访问堆区、page fault 和 MMU 流程 * 1.4 难点对比:VMA / 页表 / 虚拟地址 / 物理页 * 2. 销毁与并发:`free` / `munmap`、线程和页表更新 * 2.1 C++ 语义:

By Ne0inhk
【零基础学java】(等待唤醒机制,线程池补充)

【零基础学java】(等待唤醒机制,线程池补充)

等待唤醒机制 生产者和消费者(常见方法) void wait()当前线程等待,直到被其他线程唤醒 void notify()随机唤醒单个线程 void notifyAll()唤醒所有线程 等待唤醒机制的阻塞队列方式实现 put数据时:放不进去会等着,叫做阻塞 take数据时:取出第一个,取不到的等着 线程的六种状态 线程池 线程池的作用  1减少线程创建和销毁的开销 * 问题:每次需要任务时都创建新线程,完成后立即销毁,会消耗大量CPU和内存资源。 * 解决:线程池复用已创建的线程,避免频繁创建/销毁。 2. 控制并发.数量,防止系统过载 * 问题:无限制创建线程可能导致: * 内存耗尽 * CPU过度切换(上下文切换开销大) * 系统不稳定 * 解决:线程池设置最大线程数,控制同时运行的线程数量。 3. 提高响应速度 * 任务到达时,通常已有空闲线程可以立即执行,无需等待线程创建。

By Ne0inhk
《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——构造正/倒排索引(中篇)》

《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——构造正/倒排索引(中篇)》

前引:这是一个聚焦基础搜索引擎核心工作流的实操项目,基于 C/C++ 技术生态落地:从全网爬虫抓取网页资源,到服务器端完成 “去标签 - 数据清洗 - 索引构建” 的预处理,再通过 HTTP 服务接收客户端请求、检索索引并拼接结果页返回 —— 完整覆盖了轻量级搜索引擎的端到端逻辑。项目采用 C++11、STL、Boost 等核心技术栈,搭配 CentOS 7 云服务器 + GCC 编译环境(或 VS 系列开发工具)部署,既适配后端工程的性能需求,也能通过可选的前端技术(HTML5/JS 等)优化用户交互,是理解搜索引擎底层原理与 C++ 工程实践的典型案例 目录 【一】Jieba分词工具 【二】正/倒排索引结构设计

By Ne0inhk
MySQL面试题合集!

MySQL面试题合集!

* 临近秋招,备战暑期实习,祝大家每天进步亿点点!Day13 * 本篇总结的是 MySQL 相关的面试题,后续会每日更新~ 一、MySQL索引分析以及相关面试题 * 参考文章:MySQL索引分析以及相关面试题 二、MySQL主从复制与表拆分相关问题总结 * 参考文章: MySQL主从复制与表拆分相关问题总结 三、MySQL如何解决幻读和不可重复度? * 参考文章:MySQL如何解决幻读和不可重复度? 四、MySQL中联表查询条件WHERE和ON的区别? * 参考文章:MySQL中联表查询条件WHERE和ON的区别? 五、MySQL基础知识相关面试题总结 * 参考文章:MySQL基础知识相关面试题总结 六、MySQL锁相关问题学习 * 参考文章:MySQL锁相关问题学习 最后再安利一篇mysql面试题合集: https://blog.ZEEKLOG.net/v123411739/article/details/106893197 总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支

By Ne0inhk