Leetcode最长公共前缀
-
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串
""。
示例一
输入: ["flower","flow","flight"] 输出: "fl"
示例二
输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。
- 说明: 所有输入只包含小写字母
a-z。
题解
1、垂直扫描法
先拿到数组中第一个字符串的第一个字符,然后与数组中其它字符串的第一个字符对比,如果相等,那么继续扫描下一个位置;如果不相等,则返回。
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.size() == 0) return "";
int min = strs[0].size();
for(int k=1; k<strs.size(); k++){
if(strs[k].size() < min) min = strs[k].size();
}
for(int i=0; i<min; i++){
for(int j=1; j<strs.size(); j++){
if(strs[0][i] != strs[j][i]){
strs[0][i] = '\0'; // '\0'表示字符串最后一个位置
break;
}
}
}
if(strs[0].size() > min) strs[0][min] = '\0';
return strs[0];
}
};
2. 水平扫描法
对于字符串数组S1, S2, ...Sn,先求得S1和S2的最长公共前缀,然后用求得的公共前缀和S3进行操作,这样一直执行下去。执行过程中,如果求得的最长公共前缀为空,那么直接返回""
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.size() == 0) return "";
string a = strs[0];
string s = ""; // 存储最长公共前缀
for(int i=1; i<strs.size(); i++){
int j =0;
while(j < a.size()){
if(a[j] == strs[i][j]) {
s += a[j];
j++;
}
else j = a.size(); // 目的是退出while循环
}
a = s;
if(a == "") return ""; // 最长公共前缀为空,直接返回
s = "";
}
return a;
}
};
3. 分治法
为了求LCP(Si, Sj),可以将它分为两个子问题LCP(Si, Smid)和LCP(Smid+1, Sj),其中,mid = (i + j) / 2。所以,我们只需要求得两个子问题的解lcp_LEFT和lcp_RIGHT,然后再对两个解取的公共部分即可。
class Solution { public: string longestCommonPrefix(vector<string>& strs) { if(strs.size() == 0) return ""; int mid = strs.size() / 2; string LCP_left = LCP(0, mid-1, strs); string LCP_right = LCP(mid, strs.size()-1, strs); string s = ""; int min = (LCP_left.size() > LCP_right.size())?LCP_right.size():LCP_left.size(); for(int i=0; i<min; i++){ if(LCP_left[i] == LCP_right[i]) s += LCP_left[i]; else break; } return s; } string LCP(int start, int end, vector<string> strs){ int min = strs[start].size(); for(int k=start+1; k<=end; k++){ if(strs[k].size() < min) min = strs[k].size(); } for(int i= 0; i<min; i++){ for(int j=start+1; j<=end; j++){ if(strs[start][i] != strs[j][i]){ strs[start][i] = '\0'; break; } } } if(strs[start].size() > min) strs[start][min] = '\0'; return strs[start]; } };
4、二分查找法
想法就是应用二分查找法找到所有字符串的公共前缀的最大长度L。算法的查找区间是[1, minLen],其中minLen是输入数据中最短的字符串的长度,同时也是答案的最长可能长度。每一次将区间一分为二,然后丢弃一定不包含最终答案的那一个。
class Solution { public: string longestCommonPrefix(vector<string>& strs) { if(strs.size() == 0) return ""; if(strs.size() == 1) return strs[0]; int min = strs[0].size(); for(int i=1; i<strs.size(); i++){ if(strs[i].size() < min) min = strs[i].size(); } int low = 1; int high = min; while(low <= high){ int middle = (low + high) / 2; if(LCP(strs, middle)) low = middle + 1; else high = middle - 1; } cout<<low<<high; strs[0][(high+low)/2] = '\0'; return strs[0]; } bool LCP(vector<string> strs, int len){ bool flag = true; // 指示字符串的前len个字符是否都相等 for(int j=0; j<len; j++){ for(int k=1; k<strs.size(); k++){ if(strs[0][j] != strs[k][j]) { flag = false; break; } } } if(!flag) return false; else return true; } };
5. 仅比较两个字符串
首先,假设有两个单词 "abcd"和"abcde",那么在一本涵盖了所有字母排列的字典中,这两个单词之间的单词也一定有前缀"abcd"(可以看做26进制的数)
于是,我们就只需要比较最小字典序的字符串和最大字典序的字符串。那么sort一遍数组,然后取strs[0]与strs[n-1],比较求解即可
class Solution { public: string longestCommonPrefix(vector<string>& strs) { if(strs.size() == 0) return ""; // sort(first, last, comp): first排序数组起始地址,last排序数组最后一个元素的后一个地址,comp排序方法,不写时默认是升序排序。 sort(strs.begin(), strs.end()); // 默认是从大到小排序 int i=0; for(i=0; i<min(strs[0].size(), strs[strs.size()-1].size()); i++){ if(strs[0][i] != strs[strs.size()-1][i]) break; } return strs[0].substr(0, i); } };

浙公网安备 33010602011771号