用Kotlin和OOP的写法,也许比OI风格的代码可读性更好吧。
这是代码片段,总的来说,感觉class和封装能够更好地让代码具有自描述的能力,稍微留心一下把变量名和函数名取好的话,其实并不需要很多注释。这里写注释更多是为了记下思路,或者算是教学目的的了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| data class TrieNode(val char: Char?, val children: MutableList<TrieNode> = mutableListOf()) {
private fun append(node: TrieNode): TrieNode { if (children.none { it.char == node.char }) { children.add(node) return node } else { throw IllegalStateException("Double child detected") } }
private fun lookup(c: Char) = children.firstOrNull { it.char == c }
fun insert(s: String): Unit { if (s.isNotEmpty()) { val firstNode = lookup(s.first()) ?: append(TrieNode(s.first())) firstNode.insert(s.drop(1)) } }
fun find(s: String): Boolean { return if (s.isNotEmpty()) { lookup(s.first())?.find(s.drop(1)) ?: false } else { true } } }
|
要从一个字符串构建出对应的Trie,也就是把这个字符串的所有后缀都输入进去:
1 2 3 4 5 6 7 8 9 10
| fun buildSuffixTrie(s: String): TrieNode { val topTree = TrieNode(null)
for (i in s.indices) { topTree.insert(s.slice(i..< s.length)) }
return topTree }
|
大概是这样:
1 2 3 4
| val trie = buildSuffixTrie("quickfoxjump")
trie.find("quickfox").let(::println) trie.find("quickdog").let(::println)
|
也可以手动构建:
1 2 3 4 5 6 7 8 9 10 11 12
| val topTree = TrieNode(null)
topTree.insert("aa") topTree.insert("aba") topTree.insert("ba") topTree.insert("caa") topTree.insert("cab") topTree.insert("aba") topTree.insert("cc") topTree.insert("caab")
topTree.find("caab")
|
总的来讲,这套写法性能和效率都不怎么样,哪怕纯OOP也有效率更高的(比如使用标准库的字典或数组,减少链式调用或字符串上的方法的使用,用更多的循环,之类的)。但总体来说效率也还过得去。
主要还是可读性会比较好。
当然Trie也算一种比较简单的数据结构,如果能够实现效率更好的后缀树数据结构的话,也算一种提升。
这次大概就先到这里了。