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.
solution 1: brute force
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length < 1) return "";
String prefix = "";
int minLen = Integer.MAX_VALUE;
for (int k = 0; k < strs.length; k++) {
minLen = Math.min(minLen, strs[k].length());
}
int i = 0;
while (i < minLen) {
char temp = strs[0].charAt(i);
for (int j = 0; j < strs.length; j++) {
if (temp != strs[j].charAt(i)) {
return prefix;
}
}
prefix = prefix + strs[0].charAt(i);
i++;
}
return prefix;
}
solution 2: horizontal scanning
基本思路是
L
C
P
(
S
1
.
.
.
S
n
)
=
L
C
P
(
L
C
P
(
L
C
P
(
S
1
,
S
2
)
,
S
3
)
,
.
.
.
S
n
)
LCP(S_{1}...S_{n}) =LCP(LCP(LCP(S_{1},S_{2}),S_{3}),...S_{n})
LCP(S1...Sn)=LCP(LCP(LCP(S1,S2),S3),...Sn)
算法:对
[
S
1
,
S
2
,
.
.
.
S
n
]
[S_{1}, S_{2}, ...S_{n}]
[S1,S2,...Sn]进行循环,在每一次循环 i 中都找到
L
C
P
(
S
1
.
.
.
S
i
)
LCP(S_{1}...S_{i})
LCP(S1...Si),最后得到
L
C
P
(
S
1
.
.
.
S
n
)
LCP(S_{1}...S_{n})
LCP(S1...Sn),需要注意的是如果循环中出现prefix = ""需要直接return“”
public String longestCommonPrefix3(String[] strs) {
if (strs == null || strs.length < 1) return "";
String prefix = "";
for (int i = 0; i < strs[0].length(); i++) {
char temp = strs[0].charAt(i);
for (int j = 1; j < strs.length; j++) {
// return the prefix, when there is a mismatch or
// one of the string is running out
if (strs[j].charAt(i) != temp || i == strs[j].length()) {
return prefix;
}
}
prefix = prefix + temp;
}
return prefix;
}
solution 3: vertical scanning
vertical scanning和上面brute force的思路一致
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) return "";
for (int i = 0; i < strs[0].length() ; i++){
char c = strs[0].charAt(i);
for (int j = 1; j < strs.length; j ++) {
if (i == strs[j].length() || strs[j].charAt(i) != c)
return strs[0].substring(0, i);
}
}
return strs[0];
}
solution 4: binary search
上面三种solution的复杂度都是
O
(
n
1
+
n
2
+
n
3
+
.
.
.
n
n
)
O(n_{1}+n_{2}+n_{3}+...n_{n})
O(n1+n2+n3+...nn)
binary search并不能降低复杂度, divide and conquer
L
C
P
(
S
1
.
.
.
S
n
)
=
L
C
P
(
L
C
P
(
L
C
P
(
S
1
,
S
2
)
,
S
3
)
,
.
.
.
S
n
)
LCP(S_{1}...S_{n}) =LCP(LCP(LCP(S_{1},S_{2}),S_{3}),...S_{n})
LCP(S1...Sn)=LCP(LCP(LCP(S1,S2),S3),...Sn)同样有:
L
C
P
(
S
1
.
.
.
S
n
)
=
L
C
P
(
L
C
P
(
S
1
,
S
2
,
.
.
.
S
k
)
,
L
C
P
(
S
k
+
1
,
S
k
+
2
,
.
.
.
S
n
)
)
LCP(S_{1}...S_{n}) =LCP(LCP(S_{1},S_{2},... S_{k}), LCP(S_{k+1}, S_{k+2},... S_{n}) )
LCP(S1...Sn)=LCP(LCP(S1,S2,...Sk),LCP(Sk+1,Sk+2,...Sn))由于上面的公式成立所以可以采用divide and conquer。
binary search 复杂度为 O ( ( n 1 + n 2 + n 3 + . . . n n ) ∗ l o g n ) O((n_{1}+n_{2}+n_{3}+...n_{n})*logn) O((n1+n2+n3+...nn)∗logn),其中n为字符串数组的大小。
public String longestCommonPrefix4(String[] strs) {
if (strs == null || strs.length < 1) return "";
// search for the shortest string
int minLem = strs[0].length();
for (int i = 1; i < strs.length; i++) {
minLem = Math.min(minLem, strs[i].length());
}
int lo = 0;
int hi = minLem;
while (lo <= hi) {
int mid = lo + (hi - lo)/2;
if (isCommonPrefix(strs, mid)) lo = mid + 1;
else hi = mid - 1;
}
return strs[0].substring(0, (hi+lo)/2);
}
public boolean isCommonPrefix(String[] strs, int len) {
String temp = strs[0].substring(0, len);
for (int i = 1; i < strs.length; i++) {
if (!temp.equals(strs[i].substring(0, len)))
return false;
}
return true;
}