我的解法
暴力法(垂直扫描法)
求得字符串长度的最小值,最长公共前缀的长度一定不会超过这个最小值 minLen
从第一个字符串依次取 minLen
个字符,每取一个字符就看其余字符串的同一位置是否是该字符,若所有字符串的同一位置都是该字符,将其加入到结果串 com
中,否则,退出循环,该字符前面的部分即为最大前缀串。
class Solution {
public String longestCommonPrefix(String[] strs) {
String com = "";
int minLen = 200;
for(int i = 0;i < strs.length;++i)
minLen = strs[i].length() < minLen ? strs[i].length() : minLen;
for(int i = 0;i < minLen;++i){
char tmp = strs[0].charAt(i);
int j;
for(j = 0;j < strs.length;++j)
if(strs[j].charAt(i) != tmp)
break;
if(j == strs.length)
com += tmp;
else
break;
}
return com;
}
}
看思路自己实现
水平扫描法
假设第一个字符串为结果串,用结果串和后续的字符串依次比较,后续的字符串不是以 com
为前缀,则结果串长度减一,直至结果串为所有后续字符串的前缀或者返回 ""
若字符串 com
是 str
的前缀,则 str.indexOf(com) == 0
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0)
return "";
String com = strs[0];
for(int i = 1;i < strs.length;++i){
while(strs[i].indexOf(com) != 0){
com = com.substring(0,com.length()-1);
if(com.length() == 0)
return "";
}
}
return com;
}
}
时间复杂度 : O ( n 2 ) O(n^2) O(n2)
字典序
字典序这个点没有想到,排成字典序,第一个和最后一个的公共前缀就是这个字符串组的最大公共前缀
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0)
return "";
if(strs.length == 1)
return strs[0];
//if (strs == null || strs.length == 0) {
// return "";
//}
Arrays.sort(strs,new Cmp());
String com = strs[0];
//当有多个最短字符串,则都需要比较
int i = 1;
while(i != strs.length && strs[i].length() == strs[0].length()){
while(strs[i].indexOf(com) != 0){
com = com.substring(0,com.length()-1);
}
i++;
}
//当有多个最长字符串
int j = strs.length-2;
while(j != 0 && strs[j].length() == strs[strs.length-1].length()){
while(strs[j].indexOf(com) != 0){
com = com.substring(0,com.length()-1);
}
j--;
}
for(int k = 0;k < strs.length;++k)
while(strs[k].indexOf(com) != 0){
com = com.substring(0,com.length()-1);
if(com.length() == 0)
return "";
}
return com;
}
}
class Cmp implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
// TODO 自动生成的方法存根
return o1.length() - o2.length();
}
}
。。。。。。终于是过了,仔细想了下,字典序行不通,像 ["baab","bacb","b","cbc"]
这个示例,排序后 ["b","cbc","baab","bacb"]
,最后还得用水平扫描补一下。
java排序补充
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
private List<Type> list = new ArrayList<>();
Collections.sort(list, new Comparator<Type>() {
@Override
public int compare(Type o1, Type o2) {
return o1.compareTo(o2);// o1>o2
}
});
//倒序排列
Collections.reverse(list);
题解
二分查找法
第一次见这么用,记下来:也是垂直扫描的改进,对于不匹配的情况,只需要原来一般时间就可以扫描到。
由于最长公共前缀不会超过最短的字符串长度 m i n L e n minLen minLen ,所以,只需要在 [ 0 , m i n L e n ] [0,minLen] [0,minLen] 中判断最短公共前缀。
而对于
m
i
n
L
e
n
minLen
minLen 长度的字符串,用二分查找,折半查找可以更快的找到失配字符。
每次取查找范围的中间值
m
i
d
mid
mid,判断每个字符串的长度为
m
i
d
mid
mid 的前缀是否相同,
- 如果相同则最长公共前缀的长度一定大于或等于 m i d mid mid
- 如果不相同则最长公共前缀的长度一定小于 m i d mid mid
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
int minLength = Integer.MAX_VALUE;
for (String str : strs) {
minLength = Math.min(minLength, str.length());
}
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].substring(0, low);
}
public boolean isCommonPrefix(String[] strs, int length) {
String str0 = strs[0].substring(0, length);
int count = strs.length;
for (int i = 1; i < count; i++) {
String str = strs[i];
for (int j = 0; j < length; j++) {
if (str0.charAt(j) != str.charAt(j)) {
return false;
}
}
}
return true;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
分治法
使用分治法得到字符串数组中的最长公共前缀。
L C P ( S 1 , . . . , S n ) = L C P ( L C P ( S 1 , . . . , S k ) , L C P ( S k + 1 , S n ) ) LCP(S_1,...,S_n) = LCP(LCP(S_1,...,S_k),LCP(S_{k+1},S_n)) LCP(S1,...,Sn)=LCP(LCP(S1,...,Sk),LCP(Sk+1,Sn))
垂直扫描法的改进。
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
} else {
return longestCommonPrefix(strs, 0, strs.length - 1);
}
}
public String longestCommonPrefix(String[] strs, int start, int end) {
if (start == end) {
return strs[start];
} else {
int mid = (end - start) / 2 + start;
String lcpLeft = longestCommonPrefix(strs, start, mid);
String lcpRight = longestCommonPrefix(strs, mid + 1, end);
return commonPrefix(lcpLeft, lcpRight);
}
}
public String commonPrefix(String lcpLeft, String lcpRight) {
int minLength = Math.min(lcpLeft.length(), lcpRight.length());
for (int i = 0; i < minLength; i++) {
if (lcpLeft.charAt(i) != lcpRight.charAt(i)) {
return lcpLeft.substring(0, i);
}
}
return lcpLeft.substring(0, minLength);
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-common-prefix/solution/zui-chang-gong-gong-qian-zhui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间复杂度 O ( m n ) O(mn) O(mn)
问题
没想到字典序,还是刷题基础不牢,像位运算,回文串,排序,查找这些基础没练习过,需要从简单的入手,练好基础再来刷这些题就不止 O ( n 2 ) O(n^2) O(n2) 了
分治法其实很常用,一看到二分查找就想能不能用分治。以后记住,一组数据一定可以两个两个处理或者一半一半处理。
感受就是做好一道题比多做几道简单题有用。