14. Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string ""
.
Example 1:
Input: ["flower","flow","flight"] Output: "fl"
Example 2:
Input: ["dog","racecar","car"] Output: "" Explanation: There is no common prefix among the input strings.
Note:
All given inputs are in lowercase letters a-z
.
题目大意
给出一组字符串数组,找出数组中最长的前缀(LCP,longest common prefix)。
方法一:暴力法
解题思路:
1.找出数组中最短的字符串长度m
2.假设LCP长度为i(初始i=m),遍历数组求证前缀长度是否为i,若为i则截取长度为i的前缀,否则i--。
3.将2循环,若i=0则返回""。
AC代码:
string longestCommonPrefix(vector<string>& strs) {
int maxLength = 0;
for(auto & str : strs) {
if(str.length() > maxLength) maxLength = str.length();
}
while (maxLength > 0) {
string temp = strs[0].substr(0, maxLength);
int i;
for(i = 1; i < strs.size(); i++) {
if(strs[i].substr(0, maxLength) != temp) break;
}
if(i == strs.size()) return temp;
maxLength--;
}
return "";
}
复杂度分析:
时间复杂度:O(m*n)
空间复杂度:O(1)
方法二:分治法
解题思路:
将原数组一分为二,递归寻找LCP。
AC代码:
string LCP(string left, string right) {
int mlen = min(left.length(), right.length());
for(int i = mlen; i > 0; i--) {
string s1 = left.substr(0, i);
string s2 = right.substr(0, i);
if(s1 == s2) return s1;
}
return "";
}
string getLCP(vector<string>& strs, int left, int right) {
if(left == right) {
return strs[left];
} else {
int mid = (left + right) / 2;
string sleft = getLCP(strs, left, mid);
string sright = getLCP(strs, mid + 1, right);
return LCP(sleft, sright);
}
}
string longestCommonPrefix(vector<string>& strs) {
if (strs.empty()) return "";
return getLCP(strs, 0, strs.size() - 1);
}
复杂度分析:
时间复杂度:O(n*m)
空间复杂度:O(m*log(n))
方法三:
解题思路:
1.假设第一个字符串为前缀
2.遍历字符串判断是否为前缀,若均为前缀则输出该字符串,否则将字符串长度--
3.重复步骤2直到字符串长度为0
AC代码:
string longestCommonPrefix(vector<string>& strs) {
if (strs.empty()) return "";
string str = strs[0];
for(int i = 1; i < strs.size(); i++) {
while (strs[i].find(str) != 0) {
str = str.substr(0, str.length() - 1);
if(str.length() == 0) return "";
}
}
return str;
}
复杂度分析:
时间复杂度:O(m*n)
空间复杂度:O(1)
方法四:纵向比较
解题思路:
1.枚举前缀长度i=0
2.循环遍历数组,若i>=字符串的长度,后面字符串中的第i个字符与0号字符串不同则跳出循环
AC代码:
string longestCommonPrefix(vector<string>& strs) {
if (strs.empty()) return "";
for(int i = 0; i < strs[0].length(); i++) {
for(int j = 1; j < strs.size(); j++) {
if(i == strs[j].length() || strs[j][i] != strs[0][i])
return strs[0].substr(0, i);
}
}
return strs[0];
}
复杂度分析:
时间复杂度:O(m*n)
空间复杂度:O(1)
方法五:二分法
解题思路:
1.找出长度最小的字符串长度m
2.在[1,n]中做二分法
mid = (l+r)/2
若mid是前缀,说明前缀大于等于mid
否则前缀小于mid
AC代码:
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty()) return "";
int Min = 0x3fffffff;
for(auto & str : strs) {
if(str.length() < Min) Min = str.length();
}
int l = 1, r = Min;
while(l <= r) {
int mid = (l + r) / 2;
int i;
string p = strs[0].substr(0, mid);
for(i = 1; i < strs.size(); i++) {
if(strs[i].find(p) != 0){
r = mid - 1;
break;
}
}
if(i == strs.size()) l = mid + 1;
}
return strs[0].substr(0, (l + r) / 2);
}
复杂度分析:
时间复杂度:O(m*n)
空间复杂度:O(m*log(n))