Java Leetcode-最长的公共前缀-为什么我的运行时与解决方案相比如此缓慢?

Java Leetcode-最长的公共前缀-为什么我的运行时与解决方案相比如此缓慢?,java,string,runtime,time-complexity,Java,String,Runtime,Time Complexity,问题:编写一个函数来查找字符串数组中最长的公共前缀字符串 这是一个来自leetcode的简单问题,下面是我的答案和解决方案的答案。问题是:我的答案比运行速度快1.17%,而解决方案比运行速度快79.65%。为什么我的代码这么慢 在我们开始操作初始公共字符串之前,我们的代码非常相似。解决方案是通过在String类中调用indexof和substring函数来实现的,而我的解决方案是通过使用findCommon函数来实现的,findCommon函数由我定义 解决方案: 这是我的: publ

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

这是一个来自leetcode的简单问题,下面是我的答案和解决方案的答案。问题是:我的答案比运行速度快1.17%,而解决方案比运行速度快79.65%。为什么我的代码这么慢

在我们开始操作初始公共字符串之前,我们的代码非常相似。解决方案是通过在String类中调用indexof和substring函数来实现的,而我的解决方案是通过使用findCommon函数来实现的,findCommon函数由我定义

解决方案:

这是我的:

     public static String longestCommonPrefix(String[] strs){
         if(strs == null || strs.length == 0)
            return "";
         String result = strs[0];
         for(int index = 1; index < strs.length; index++)
            result = findCommon(result, strs[index]);   
         return result;
     }

     public static String findCommon(String a, String b){
         String common = ""; 
         for(int index = 0; index < Math.min(a.length(), b.length()); index++)
         {
             if(a.charAt(index) == b.charAt(index))
                 common += a.charAt(index); 
             else 
                 break; 
         }
         return common; 
      }

在我看来,解决方案代码看起来更简单,因为函数是在字符串库中定义的。但这并不意味着它们不存在

看看您是如何构建前缀字符串的:

     String common = ""; 
     for(int index = 0; index < Math.min(a.length(), b.length()); index++)
     {
         if(a.charAt(index) == b.charAt(index))
             common += a.charAt(index); 
         else 
             break; 
     }
     return common;
Java必须创建一个全新的字符串对象,该对象是通过在现有字符串公共段的末尾添加一个新字符形成的。这意味着制作长度为p的前缀字符串的成本最终为Op2。如果总共有n个字符串,那么程序的运行时将类似于Onp2

将其与参考溶液进行对比:

pre = pre.substring(0,pre.length()-1);

在许多Java实现中,创建子字符串的操作需要时间O1,因为新字符串可以与原始字符串共享底层字符数组,并对一些索引进行了调整以考虑新的开始索引。这意味着使用p前缀的成本将是Op而不是Op2,这可能导致较长字符串的性能大幅提高。

I用户尝试解决这个问题。您可以尝试使用用户trie

#define MAX 30    //the total number of alphabet is 26, a...z

struct DicTrie{
    bool isTerminal;//是否是单词结束标志
    int  count;     //当前字符串出现次数
    int  branchCount;    //计数当前节点的孩子数
    struct DicTrie *next[MAX ]; //每个节点 最多 有 MAX 个孩子节点 结构体嵌套
};


int insertTrie(struct DicTrie *root ,char *targetString)
{
    if (!targetString) {
        return 0;
    }
    int len = strlen(targetString);
    if (len <= 0) {
        return 0;
    }
    struct DicTrie *head = root;
    for (int i = 0; i < len; i ++) {
        int res = (int)(targetString[i] - 'a');//当前小写字母对应数字
        if (head->next[res] == NULL) { //如果是空节点
            head->next[res] = (struct DicTrie *)malloc(sizeof(struct DicTrie));//new DicTrie;//则插入新节点元素
            head = head->next[res]; //更新头指针 并初始化
            head->count = 0;        //
            for (int j = 0; j < MAX; j ++) {
                head->next[j] = NULL;
                head->isTerminal = false;
            }
            head->branchCount = 1;//一个分支
        } else {
            head = head->next[res];
            head->branchCount ++;//分支累计
        }
    }
    head->count ++;//每次插入一个,响应计数都增加1
    head->isTerminal = true;
    return head->count;
}

char* longestCommonPrefix(char** strs, int strsSize) {

    int len = strsSize;
    //边界处理
    if (len == 0) {
        return "";
    }
    if (len == 1) {
        return strs[0];
    }
    //组织字典树
    struct DicTrie *root = NULL;
    root = (struct DicTrie *)malloc(sizeof(struct DicTrie));
    root->count = 0;
    root->branchCount = 0;
    for (int  i = 0; i < MAX; i ++) {
        root->next[i] = NULL; // 空节点
        root->isTerminal = false; //
    }
    //
    for (int i = 0;i < len; i ++) {
        insertTrie(root, strs[i]);
    }
    //
    int preIndex = 0;

    struct DicTrie *head = root;
    bool isFlag = false;
    int i = 0;
    int count = strlen(strs[0]);//任意一字符串都可以 从strs[0]中查即可
    for (preIndex = 0; preIndex< count; preIndex ++) {
        int targetIndex = strs[0][preIndex] - 'a';
        head = head->next[targetIndex];
        if (head->branchCount == len) {
            i ++;//拿到合法前缀的计数
            isFlag = true;
        }
    }
    if (isFlag) {
        preIndex = i;
    } else {
        preIndex = 0;
    }
    strs[0][preIndex] = '\0';
    return  strs[0];
}
运行速度正常。

pre = pre.substring(0,pre.length()-1);
#define MAX 30    //the total number of alphabet is 26, a...z

struct DicTrie{
    bool isTerminal;//是否是单词结束标志
    int  count;     //当前字符串出现次数
    int  branchCount;    //计数当前节点的孩子数
    struct DicTrie *next[MAX ]; //每个节点 最多 有 MAX 个孩子节点 结构体嵌套
};


int insertTrie(struct DicTrie *root ,char *targetString)
{
    if (!targetString) {
        return 0;
    }
    int len = strlen(targetString);
    if (len <= 0) {
        return 0;
    }
    struct DicTrie *head = root;
    for (int i = 0; i < len; i ++) {
        int res = (int)(targetString[i] - 'a');//当前小写字母对应数字
        if (head->next[res] == NULL) { //如果是空节点
            head->next[res] = (struct DicTrie *)malloc(sizeof(struct DicTrie));//new DicTrie;//则插入新节点元素
            head = head->next[res]; //更新头指针 并初始化
            head->count = 0;        //
            for (int j = 0; j < MAX; j ++) {
                head->next[j] = NULL;
                head->isTerminal = false;
            }
            head->branchCount = 1;//一个分支
        } else {
            head = head->next[res];
            head->branchCount ++;//分支累计
        }
    }
    head->count ++;//每次插入一个,响应计数都增加1
    head->isTerminal = true;
    return head->count;
}

char* longestCommonPrefix(char** strs, int strsSize) {

    int len = strsSize;
    //边界处理
    if (len == 0) {
        return "";
    }
    if (len == 1) {
        return strs[0];
    }
    //组织字典树
    struct DicTrie *root = NULL;
    root = (struct DicTrie *)malloc(sizeof(struct DicTrie));
    root->count = 0;
    root->branchCount = 0;
    for (int  i = 0; i < MAX; i ++) {
        root->next[i] = NULL; // 空节点
        root->isTerminal = false; //
    }
    //
    for (int i = 0;i < len; i ++) {
        insertTrie(root, strs[i]);
    }
    //
    int preIndex = 0;

    struct DicTrie *head = root;
    bool isFlag = false;
    int i = 0;
    int count = strlen(strs[0]);//任意一字符串都可以 从strs[0]中查即可
    for (preIndex = 0; preIndex< count; preIndex ++) {
        int targetIndex = strs[0][preIndex] - 'a';
        head = head->next[targetIndex];
        if (head->branchCount == len) {
            i ++;//拿到合法前缀的计数
            isFlag = true;
        }
    }
    if (isFlag) {
        preIndex = i;
    } else {
        preIndex = 0;
    }
    strs[0][preIndex] = '\0';
    return  strs[0];
}