我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第15篇文章,最长公共前缀 [分治 & 抽象二分练习] - 掘金 (juejin.cn)
前言
对于一个问题,采用一题多解,才能深刻理解其考察的知识点,进行举一反三。最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。
一、最长公共前缀
二、一题多解
1、纵向对比
public String longestCommonPrefix(String[] strs) {
for (int i = 0; i < strs[0].length(); i++) {
char ch = strs[0].charAt(i);
for (int j = 1; j < strs.length; j++) {
if (i == strs[j].length() || strs[j].charAt(i) != ch) return strs[0].substring(0, i);
}
}
return strs[0];
}
2、横向对比
// idea6:横向扫描(暴力之一)
public String longestCommonPrefix6(String[] strs) {
String prefix = strs[0];
for (String s : strs) prefix = compareStr(prefix, s);
return prefix;
}
private String compareStr(String s1, String s2) {
int idx = 0;
while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;
return s1.substring(0, idx);
}
3、最值对比
public String longestCommonPrefix3(String[] strs) {
String min = strs[0], max = strs[0];
for (String str : strs) {
// bug1:字符串的compare和integer的不一样,并非-1 / 0 / 1,而是长度相减作为返回值。
if (min.compareTo(str) > 0) min = str;
if (max.compareTo(str) < 0) max = str;
}
return compareStr(min, max);
}
private String compareStr(String s1, String s2) {
int idx = 0;
while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;
return s1.substring(0, idx);
}
4、分治
private String partition(String[] strs, int left, int right) {
if (left == right) return strs[left];
int mid = left + (right - left >> 1);
String s1 = partition(strs, left, mid);
String s2 = partition(strs, mid + 1, right);
return compareStr(s1, s2);
}
private String compareStr(String s1, String s2) {
int idx = 0;
while (idx < s1.length() && idx < s2.length() && s1.charAt(idx) == s2.charAt(idx)) ++idx;
return s1.substring(0, idx);
}
5、二分
public String longestCommonPrefix5(String[] strs) {
String s = strs[0];
int low = 0, high = s.length();
while (low < high) {
int mid = low + (high - low + 1 >> 1);// 为了low不越界,这里必须+1防止死循环。
String midStr = s.substring(0, mid);
if (isMatchAll(strs, midStr)) low = mid;
else high = mid - 1;
}
return s.substring(0, low);
}
private boolean isMatchAll(String[] strs, String str) {
for (String s : strs) {
if (s.length() < str.length() || !str.equals(s.substring(0, str.length()))) return false;
}
return true;
}
总结
1)最长公共前缀,可横向对比 / 竖向对比 / 最值对比 / 分治 / 二分方法来完成题解。对于分治来讲,可多线程操作加快速度;对于二分,考察对抽象二分的理解,将二分规则进行抽象。
参考文献
[1] LeetCode 最长公共前缀