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