Description:
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 “”. Do it now!
方法1:Vertical scanning(垂直扫描)
- 思想:同一列从上往下比较。
- 实现代码:
public String longestCommonPrefix(String[] strs) { if(strs.length == 0) return ""; for(int i = 0; i < strs[0].length(); i++) { for(String s : strs) { if (i >= s.length() || s.charAt(i) != strs[0].charAt(i)) return strs[0].substring(0, i); } } return strs[0]; }
- 时间复杂度:\(O(S)\),S是所有字符串的总和。空间复杂度:\(O(1)\)
方法2:Horizontal scanning(水平扫描)
- 思想:先找到 \(S_1\) 和 \(S_2\) 的最长共前缀 \(LCP(S_1, S_2)\),再找到 \(LCP(S_1, S_2)\) 和 \(S_3\) 的最长公共前缀 \(LCP(LCP(S_1, S_2), S_3)\),这样一直到\(S_n\)。
\(LCP(S_1, S_n) = LCP(LCP(LCP(S_1, S_2), S_3),…S_n)\)
- 实现代码:
public String longestCommonPrefix(String[] strs) { if(strs.length == 0) return ""; String prefix = strs[0]; for(int i = 1; i < strs.length; i++) { while (strs[i].indexOf(prefix) != 0) { prefix = prefix.substring(0, prefix.length() - 1); if (prefix == "") return ""; } } return prefix; }
- 时间复杂度:\(O(S)\),S是所有字符串的总和。空间复杂度:\(O(1)\)
方法3:Divide and conquer(分治法)
- 思想:由方法2的公式可以注意到 \(LCP(S_1, S_n) = LCP(LCP(S_1…S_k), LCP(S_{k+1}…S_n))\),将 \(LCP(S_1, S_n)\) 问题划分为求2个子问题 \(LCP(S_1, S_{mid})\) 和 \(LCP(S_{mid+1}…S_j)\),其中 \(mid = \frac{i+j}{2}\)。
- 实现代码:
public String longestCommonPrefix(String[] strs) { if (strs.length == 0) return ""; return longestCommonPrefix(strs, 0, strs.length - 1); } private String longestCommonPrefix(String[] strs, int l, int r){ if (l == r) return strs[l]; int mid = (l + r)/2; String lcpl = longestCommonPrefix(strs, l, mid); String lcpr = longestCommonPrefix(strs, mid+1, r); return commonPrefix(lcpl, lcpr); } String commonPrefix(String l, String r) { int min = Math.min(l.length(), r.length()); for (int i = 0; i < min; i++) { if (l.charAt(i) != r.charAt(i)) return l.substring(0, i); } return l.substring(0, min); }
- 时间复杂度:\(O(S)\)(官方给的),感觉不对,我觉得是 \(O(m*logn)\)。
- 空间复杂度:\(O(m*logn)\),\(n\) 是字符串数,\(m\) 是字符串的长度。由于在堆栈中存储递归调用,有 \(logn\) 的递归调用,每个需要 \(m\) 的空间存储结果。
方法4:Binary search(二分搜索法)
- 思想:算法的搜索空间是 \((0…min\_len)\),每一次将搜索空间划分成两部分,其中一部分在判断是否为公共前缀之后可以丢弃。有两种可能情况:
- \(S[1…mid]\) 是公共前缀,则这部分可以丢弃掉,继续往前寻找更长的部分。
- \(S[1…mid]\) 不是公共前缀,则 \(S[mid+1…min\_len]\) 可以丢弃掉,因为它一定不是公共前缀。
- 实现代码:
public String longestCommonPrefix(String[] strs) { if (strs.length == 0) return ""; int min_len = strs[0].length(); for(String s: strs) { min_len = Math.min(min_len, s.length()); } int low = 1, high = min_len; while (low <= high) { int mid = (low + high) / 2; if (isCommonPrefix(strs, mid)) { low = mid + 1; } else { high = mid - 1; } } return strs[0].substring(0, (low+high)/2); } Boolean isCommonPrefix(String[] strs, int len) { String s0 = strs[0].substring(0, len); for (int i = 1; i < strs.length; i++) { if (!strs[i].startsWith(s0)) return false; } return true; }
- 时间复杂度:\(O(S*logm)\),空间复杂度:\(O(1)\)
我很可爱,请给我钱
- Post link: http://yoursite.com/leetcode/14-LCP/
- Copyright Notice: All articles in this blog are licensed under unless stating additionally.
若您想及时得到回复提醒,建议跳转 GitHub Issues 评论。
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues