算法-Trie树/- 最长公共前缀

深藏阁楼爱情的钟 2023-02-18 01:46 125阅读 0赞

算法-Trie树/- 最长公共前缀

1 题目概述

1.1 题目出处

https://leetcode-cn.com/problems/longest-common-prefix/

1.2 题目描述

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

示例 1:

输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:

输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。

2 Trie树-递归版

2.1 思路

构建Trie树,第一个单词先正常插入。

依次遍历后续单词,insert的时候如果发现一个字符在当前Trie树中不存在,说明只能由之前的所有字符构成公共前缀,直接返回即可。

如果存在,还需要判断当前查找长度是否大于之前最短前缀长度,大于就直接退出不再查找了。

2.2 代码

  1. class Solution {
  2. public String longestCommonPrefix(String[] strs) {
  3. String result = "";
  4. if(strs == null || strs.length == 0){
  5. return result;
  6. }
  7. Trie t = new Trie();
  8. String str = strs[0];
  9. String prefix = str;
  10. t.insert(str);
  11. for(int i = 1; i < strs.length; i++){
  12. String tmpPrefix = t.insertAndFindPrefix(strs[i], "");
  13. if(tmpPrefix.length() < prefix.length()){
  14. prefix = tmpPrefix;
  15. if(prefix.length() == 0){
  16. // 如果发现已经没有公共前缀,直接退出查找
  17. break;
  18. }
  19. }
  20. }
  21. return prefix;
  22. }
  23. class Trie {
  24. private Trie[] children;
  25. private boolean is_end;
  26. /** Initialize your data structure here. */
  27. public Trie() {
  28. children = new Trie[26];
  29. }
  30. /** Inserts a word into the trie. */
  31. public void insert(String word) {
  32. if(word == null || word.trim().length() == 0){
  33. return;
  34. }
  35. char first = word.charAt(0);
  36. int index = first - 'a';
  37. Trie child = children[index];
  38. if(child == null){
  39. child = new Trie();
  40. children[index] = child;
  41. }
  42. word = word.substring(1);
  43. if(word.length() > 0){
  44. child.insert(word);
  45. }else{
  46. child.is_end = true;
  47. }
  48. }
  49. public String insertAndFindPrefix(String word, String prefix, int prefixLength) {
  50. if(word == null || word.trim().length() == 0){
  51. return prefix;
  52. }
  53. char first = word.charAt(0);
  54. int index = first - 'a';
  55. Trie child = children[index];
  56. if(child == null){
  57. return prefix;
  58. }
  59. prefix = prefix + first;
  60. word = word.substring(1);
  61. if(word.length() > 0){
  62. if(--prefixLength > 0){
  63. prefix = child.insertAndFindPrefix(word, prefix, prefixLength);
  64. }else{
  65. return prefix;
  66. }
  67. }else{
  68. child.is_end = true;
  69. }
  70. return prefix;
  71. }
  72. }
  73. }

2.3 时间复杂度

O(N*L)

2.4 空间复杂度

O(L)

3 Trie树-循环版

3.1 思路

思路和前面差不多,不过这里优化先将最短字符插入,以便其他字符串插入查找时可以快速结束。

还有一个优化点是使用StringBuilder记录prefix,不然会创建大量String对象。

3.2 代码

  1. class Solution {
  2. public String longestCommonPrefix(String[] strs) {
  3. String result = "";
  4. if(strs == null || strs.length == 0){
  5. return result;
  6. }
  7. if(strs.length == 1){
  8. return strs[0];
  9. }
  10. Trie t = new Trie();
  11. int shortestIndex = -1;
  12. int shortestLength = Integer.MAX_VALUE;
  13. for(int i = 0; i < strs.length; i++){
  14. if(strs[i].length() == 0){
  15. return result;
  16. } else if(strs[i].length() < shortestLength){
  17. shortestLength = strs[i].length();
  18. shortestIndex = i;
  19. }
  20. }
  21. String str = strs[shortestIndex];
  22. String prefix = str;
  23. t.insert(str);
  24. for(int i = 0; i < strs.length; i++){
  25. if(i == shortestIndex){
  26. continue;
  27. }
  28. String tmpPrefix = t.insertAndFindPrefix(strs[i], new StringBuilder(), prefix.length());
  29. if(tmpPrefix.length() < prefix.length()){
  30. prefix = tmpPrefix;
  31. if(prefix.length() == 0){
  32. // 如果发现已经没有公共前缀,直接退出查找
  33. break;
  34. }
  35. }
  36. }
  37. return prefix;
  38. }
  39. class Trie {
  40. private Trie[] children;
  41. private boolean isEnd;
  42. /** Initialize your data structure here. */
  43. public Trie() {
  44. children = new Trie[26];
  45. }
  46. /** Inserts a word into the trie. */
  47. public void insert(String word) {
  48. Trie current = this;
  49. for(char c : word.toCharArray()){
  50. int index = c - 'a';
  51. Trie child = current.children[index];
  52. if(child == null){
  53. child = new Trie();
  54. current.children[index] = child;
  55. }
  56. current = child;
  57. }
  58. current.isEnd = true;
  59. }
  60. /** Inserts a word into the trie. */
  61. public String insertAndFindPrefix(String word, StringBuilder prefix, int prefixLength) {
  62. Trie current = this;
  63. for(char c : word.toCharArray()){
  64. int index = c - 'a';
  65. Trie child = current.children[index];
  66. if(child == null){
  67. return prefix.toString();
  68. }
  69. prefix.append(c);
  70. if(--prefixLength == 0){
  71. return prefix.toString();
  72. }
  73. current = child;
  74. }
  75. return prefix.toString();
  76. }
  77. }
  78. }

3.3 时间复杂度

在这里插入图片描述
O(N*L)

3.4 空间复杂度

O(L)

发表评论

表情:
评论列表 (有 0 条评论,125人围观)

还没有评论,来说两句吧...

相关阅读

    相关 公共前缀

    题目: 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 “”。 示例 1: 输入:strs = \[“flower”,“flow”

    相关 公共前缀-Java

    //最长公共前缀 //题目描述:编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。 //示例 1: //输入: \["flowe