LeetCode面试150——14最长公共前缀

news/2024/9/23 4:03:00/

题目难度:简单

默认优化目标:最小化平均时间复杂度。

Python默认为Python3。

目录

1 题目描述

2 题目解析

3 算法原理及代码实现

3.1 横向扫描

3.2 纵向扫描

3.3 分治

3.4 二分查找

参考文献


1 题目描述

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例 1:

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

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

提示:

  • 1 <= strs.length <= 200

  • 0 <= strs[i].length <= 200

  • strs[i] 仅由小写英文字母组成

2 题目解析

输入一个字符串数组strs,输出strs中各单词的最长公共前缀。strs[i]表示第i个单词。暴力求解的方法是,选定strs[0],然后和strs[1]比较,找到它们的最长公共前缀。然后和strs[2]比,找到它们的最长公共前缀,依次类推。设strs的长度为n,单词的长度为m,平均时间复杂度为O(mn)。

3 算法原理及代码实现

3.1 横向扫描

即暴力求解法。依次遍历每个数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串后,即可得到字符串数组中的最长公共前缀。

有一个特殊情况,如果最长公共字符串为空,直接返回即可,无需继续遍历。

平均时间复杂度为O(mn),平均空间复杂度为O(1)。

C++代码实现

class Solution {
public:// 主函数:找到字符串数组中的最长公共前缀string longestCommonPrefix(vector<string>& strs) {// 如果字符串数组为空,返回空字符串if (strs.empty()) {return "";}
​// 初始化最长公共前缀为第一个字符串string maxCommonPrefix = strs[0];int n = strs.size();
​// 遍历字符串数组,从第二个字符串开始for (int i = 1; i < n; i++) {// 更新最长公共前缀maxCommonPrefix = longestCommonPrefix(maxCommonPrefix, strs[i]);// 如果最长公共前缀为空,提前退出循环if (maxCommonPrefix.empty()) {break;}}return maxCommonPrefix;}
​// 辅助函数:找到两个字符串的最长公共前缀string longestCommonPrefix(const string& str1, const string& str2) {int n=min(str1.size(),str2.size());int index=0;
​while(index<n && str1[index]==str2[index]){index++;}
​return str1.substr(0,index);}
};

Python代码实现

python">class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:n=len(strs)maxCommenPrefix=strs[0]
​if not strs:return ""
​for i in range(1,n):maxCommenPrefix=self.MCP(maxCommenPrefix,strs[i])if not maxCommenPrefix:break
​return maxCommenPrefix
​def MCP(self, str1, str2) -> str:n=min(len(str1),len(str2))index=0
​while index<n and str1[index]==str2[index]:index+=1
​return str1[:index]

3.2 纵向扫描

我们换个角度看strs,将每个单词纵向排列在一起,然后从前往后扫描每一列,直到每一列的字母不完全相同时停止。

平均时间复杂度为O(mn),平均空间复杂度为O(1)。

C++代码实现

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

Python代码实现

python">class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:if not strs:return ""n = len(strs)m = len(strs[0])for i in range(m):c = strs[0][i]for j in range(1, n):if i == len(strs[j]) or strs[j][i] != c:return strs[0][:i]return strs[0]

3.3 分治

根据横向扫描,有如下数学公式


LCP(S_1,\cdots,S_n)=LCP(LCP(S_1,\cdots,S_k),LCP(S_{k+1},\cdots,S_n))
 

其中,LCP(S_1,\cdots ,S_n)是字符串S_1\cdots S_n的最长公共前缀,1<k<n

因此,我们可以取k=mid=\frac{i+j}{2},对于LCP(S_i,\cdots,S_j)

平均时间复杂度为O(mn),平均空间复杂度为O(1)。

C++代码实现

class Solution {
public:// 主函数:找到字符串数组中的最长公共前缀string longestCommonPrefix(vector<string>& strs) {// 如果字符串数组为空,返回空字符串if (strs.empty()) {return "";} else {// 使用分治法找到最长公共前缀return longestCommonPrefix(strs, 0, strs.size() - 1);}}
​// 辅助函数:使用分治法找到字符串数组中的最长公共前缀string longestCommonPrefix(const vector<string>& strs, int start, int end) {// 如果只有一个字符串,返回该字符串if (start == end) {return strs[start];} else {// 计算中间位置int mid = (start + end) / 2;// 递归找到左半部分的最长公共前缀string lcpLeft = longestCommonPrefix(strs, start, mid);// 递归找到右半部分的最长公共前缀string lcpRight = longestCommonPrefix(strs, mid + 1, end);// 合并左右两部分的最长公共前缀return commonPrefix(lcpLeft, lcpRight);}}
​// 辅助函数:找到两个字符串的最长公共前缀string commonPrefix(const string& lcpLeft, const string& lcpRight) {int minLength = min(lcpLeft.size(), lcpRight.size());// 比较两个字符串的字符,找到公共前缀for (int i = 0; i < minLength; ++i) {if (lcpLeft[i] != lcpRight[i]) {return lcpLeft.substr(0, i);}}return lcpLeft.substr(0, minLength);}
};
​

Python代码实现

python">class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:if not strs:return ""else:return self.longestCommonPrefixHelper(strs, 0, len(strs) - 1)
​def longestCommonPrefixHelper(self, strs, start, end):if start == end:return strs[start]else:mid = (start + end) // 2lcpLeft = self.longestCommonPrefixHelper(strs, start, mid)lcpRight = self.longestCommonPrefixHelper(strs, mid + 1, end)return self.commonPrefix(lcpLeft, lcpRight)
​def commonPrefix(self, lcpLeft, lcpRight):minLength = min(len(lcpLeft), len(lcpRight))for i in range(minLength):if lcpLeft[i] != lcpRight[i]:return lcpLeft[:i]return lcpLeft[:minLength]
​

3.4 二分查找

最长公共共前缀不会超过最短长度的单词,用minLength表示最短长度单词。在[0,minLength]之间使用二分查找。

平均时间复杂度为O(mn log m),平均空间复杂度O(1)。

C++代码实现

class Solution {
public:// 函数用于找到字符串数组中的最长公共前缀string longestCommonPrefix(vector<string>& strs) {// 如果输入的字符串数组为空,返回空字符串if (!strs.size()) {return "";}// 找到数组中最短字符串的长度int minLength = min_element(strs.begin(), strs.end(), [](const string& s, const string& t) {return s.size() < t.size();})->size();int low = 0, high = minLength;// 使用二分查找法寻找最长公共前缀while (low < high) {int mid = (high - low + 1) / 2 + low;if (isCommonPrefix(strs, mid)) {low = mid;} else {high = mid - 1;}}// 返回最长公共前缀return strs[0].substr(0, low);}
​// 辅助函数用于检查给定长度的前缀是否是所有字符串的公共前缀bool isCommonPrefix(const vector<string>& strs, int length) {string str0 = strs[0].substr(0, length);int n = strs.size();// 比较每个字符串的前缀与第一个字符串的前缀for (int i = 1; i < n; i++) {string str = strs[i];for (int j = 0; j < length; j++) {if (str0[j] != str[j]) {return false;}}}return true;}
};
​

Python代码实现

python">class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:if not strs:return ""minLength = min(len(s) for s in strs)low, high = 0, minLengthwhile low < high:mid = (high - low + 1) // 2 + lowif self.isCommonPrefix(strs, mid):low = midelse:high = mid - 1return strs[0][:low]
​def isCommonPrefix(self, strs: List[str], length: int) -> bool:str0 = strs[0][:length]for i in range(1, len(strs)):if strs[i][:length] != str0:return Falsereturn True

参考文献

力扣面试经典150题

力扣官方题解


http://www.ppmy.cn/news/1509105.html

相关文章

PCIe学习笔记(19)

TLP Prefix&#xff08;前缀&#xff09;规则 以下规则适用于任何包含TLP Prefix的TLP: •对于任何TLP, TLP第0字节的Fmt[2:0]字段值为100b表示存在TLP Prefix, Type[4]位表示TLP Prefix的类型。 ◦Type[4]位的值为0b表示存在Local TLP Prefix ◦Type[4]位的值为1b表示存在…

如何应对PCDN调度算法中的数据传输延迟问题?

针对PCDN调度算法中的数据传输延迟问题&#xff0c;可以采取以下应对策略: 1.优化网络基础设施: 提升服务器和网络基础设施的性能&#xff0c;包括增加带宽、优化路由器配置和更换高性能设备&#xff0c;以减少延迟。 2.使用CDN技术: 内容分发网络(CDN)可以将数据缓存在离用…

鸿蒙开发入门day05-ArkTs语言(接口与关键字)

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;还请三连支持一波哇ヾ(&#xff20;^∇^&#xff20;)ノ&#xff09; 目录 ArkTS语言介绍 接口 接口属性 接口继承 泛型类型和函数 泛型…

ssh免输密码的运行方式

在使用SSH时&#xff0c;通过命令直接传递密码并不是一个安全的做法。但是&#xff0c;如果你确实需要自动化登录&#xff0c;可以使用sshpass工具。请注意&#xff0c;使用这种方法可能会暴露密码&#xff0c;需谨慎使用。 使用sshpass传递密码&#xff1a; 安装sshpass&…

java之UDP的发送数据和接收数据

public class SendMessageDemo {public static void main(String[] args) throws IOException {//发送数据//创建Datagramsocket对象&#xff08;快递公司&#xff09;//细节&#xff1a;//绑定端口&#xff0c;以后我们就是通过这个端口往外发送//空参&#xff1a;所有可用的端…

后端如何接收前端发出的请求中的参数?

后端接收请求中的参数 1.将参数接收到后端的实体类中1.1如果前端发出的参数在URL中1.2如果前端发出的参数在请求体中 2.将URL中的单个参数绑定到后端的单个参数中 1.将参数接收到后端的实体类中 1.1如果前端发出的参数在URL中 如果前端发出的参数在URL中&#xff0c;你可以使…

负载均衡器:LVS、Nginx、HAproxy如何选择?

目录 根据流量&#xff08;并发量&#xff09;来选型LVSNginxHAProxy总结参考 实际应用中&#xff0c;Web 服务器集群的上层要有一台负载均衡服务器&#xff0c;负载均衡设备的任务就是作为 Web 服务器流量的入口&#xff0c;挑选最合适的一台 Web 服务器&#xff0c;将客户端的…

记录|C#主界面设计【Web风格】

目录 前言一、页面效果二、布局设计2.1 左边菜单栏搭建框架Step1. panelMenu &#xff1a;Step2. panelLogoStep3. button模板Step4. 复制buttonStep5. 微调Button 2.2 界面颜色变换Step1. ThemeColor类Step2. From1.csStep3. 更换按钮点击颜色效果 2.3 按钮点击事件2.4 顶部ti…