虽然这不是您要直接询问的内容,但值得一提的是,使用 indexOf 和 substring 并不是解决此问题的好方法。
strs[i].indexOf(prefix) != 0 是一种检查字符串是否以某些内容开头的低效方法。这是因为如果它发现字符串不是以prefix 开头的,它会继续搜索其他位置的匹配项——它是否出现在那里并不重要。
更有效的检查是!strs[i].startsWith(prefix):一旦发现字符串不是以前缀开头,它就会停止。
那么,使用substring从字符串末尾截掉一个字符也是低效的:每次截掉一个字符时,它会创建一个新字符串,然后再检查一次;但是在找到匹配的前缀之前,您可能需要删除 很多 个单个字符。
您可以通过使用strs[i].regionMatches(0, prefix, 0, someLength) 避免这种“创建对象”位,其中someLength 是一个从prefix.length() 开始的int,并且您递减直到regionMatches 返回true。但这仍然是低效的,因为您一次减少一个。
如果换一种方式会更容易:从 someLength 零开始,然后递增直到:
- 等于
prefix的长度:someLength >= prefix.length()
- 等于
strs[i]的长度:someLength >= strs[i].length()
- 该位置的对应字符不匹配:
prefix.charAt(someLength) != strs[i].charAt(someLength)
这基本上是startsWith 所做的,但通过“自己”做,您可以找出字符串不同的位置。
然后,使用prefix = prefix.substring(0, someLength); 一口气砍掉它。或者根本不砍它:您可以简单地存储公共前缀的长度,并在最后执行一次子字符串。
代码如下所示:
public String longestCommonPrefix(String[] strs) {
if (strs.length == 0) return "";
int prefixLength = strs[0].length();
for (int i = 1; i < strs.length; i++) {
int s = 0;
while (s < prefixLength
&& s < strs[i].length()
&& strs[0].charAt(s) == strs[i].charAt(s)) {
++s;
}
prefixLength = s;
}
return strs[0].substring(0, prefixLength);
}