开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
1.描述
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
提示:
- 1 <= strs.length <= 200
- 0 <= strs[i].length <= 200
- strs[i] 仅由小写英文字母组成
2.分析
字符串搜索匹配中常用的方法之一字典树,用在这里还是很方便的
- 遍历String[] strs构建字典树
- 从字典树的根节点看是往下找只有一个子节点的情况,把这个自己点转化为char字符记下来
- 不光是只有一个的子节点的情况。如果说遇到的节点是标记为了字符串结尾的话,也应当结束,因为记录下来的字符组成的字符串已经达到了某个字符串的长度了
一点思考
代码中的getSingleChild()方法是判断这个节点是否只有一个子节点的,用了个遍历26个字母的方法
如果只有一个子节点的话,会返回那个子节点对应的下标,从而可以重新转换为char字符。
不过可以再优化调整下,我们可以在Node节点中再增加一个字段标记当前节点下面有多少个不同的子节点,而需要操作就变为,当在Node的children上构建新子节点的时候,同时给这个统计字段+1,这样我们在后面遍历搜索的时候就可以直接判断了
3.AC代码
class Solution {
public String longestCommonPrefix(String[] strs) {
Trie trie = new Trie();
for (String str : strs) {
trie.insert(str);
}
return trie.longestCommonPrefix();
}
class Trie{
Node root = new Node();
public void insert(String str){
if (null == str){
return;
}
int idx = -1;
Node cur = root;
while (++idx < str.length()){
int i = str.charAt(idx) - 'a';
if (cur.children[i] == null){
cur.children[i] = new Node();
}
cur = cur.children[i];
}
cur.flag = true;
}
public String longestCommonPrefix(){
StringBuffer sb = new StringBuffer();
Node cur = root;
int idx = getSingleChild(cur);
while (idx != -1){
if (cur.flag){
break;
}
//记char
sb.append((char)('a'+idx));
//找下一个
cur = cur.children[idx];
idx = getSingleChild(cur);
}
return sb.toString();
}
private int getSingleChild(Node node){
int singleChild = -1;
for (int i = 0; i < node.children.length; i++) {
if (node.children[i]!=null){
if (singleChild!=-1){
return -1;
}
singleChild = i;
}
}
return singleChild;
}
class Node{
boolean flag;
Node[] children;
public Node(){
flag = false;
children = new Node[26];
}
}
}
}