2014阿里巴巴 实习生电面题目:输出给定字符串的全部连续子串
2014-12-24 16:43
337 查看
转载请注明出处:/article/1576673.html
今天下午阿里电面的题目,给定一个字符串,输出其所有连续子串,如:给定字符串为abcd,则要输出的其全部连续子串为:a,b,c,d,ab,bc,cd,abc,bcd,abcd。
很快给出了最简单的方法,就是先从第一个字符遍历,向后输出,再从第二个字符开始遍历,向后输出,依此类推,直到开始遍历的字符为数组的最后一个字符。这个时间复杂度很高啊,要O(n*n*n)。
接下来就假设字符串很大,想优化的方法,不知道脑子是短路了还是咋地,居然联想到Trie树上去了,完全不沾边的东西。电面后想了下,感觉应该用递归,吃完饭,去图书馆用纸画了下,就是递归(还是A题A的少啊!)。后来写出来代码感觉貌似木有提高时间复杂度哦!
先贴出来吧,首先是最简单的遍历法,时间复杂度为O(n*n*n)
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/*
蛮力求解法
*/
void AllSubstring1(const char *str,int high)
{
int i, j, k;
if(!str)
return;
for(i=0;i<=high;i++)
{
for(j=i; j<=high;j++)
{
for(k = i; k<=j; k++)
printf("%c", str[k]);
printf("\t");
}
printf("\n");
}
}
而后我又减少了一层循环,增加了一个递归操作,如下:
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/*
递归求解法
*/
void AllSubstring2(const char *str,int low,int high)
{
int i;
int cur = high;
if(!str)
return;
while(low <= cur)
{
for(i=low;i<=cur;i++)
printf("%c",str[i]);
printf("\t");
cur--;
}
printf("\n");
if(low<high)
{
AllSubstring2(str,low+1,high);
}
}
但是感觉时间复杂度没有提高啊(分治策略的递归代替循环,可以将时间复杂度从O(n)降到O(logn),当然是每次将问题减到一半分治策略,若果是类似斐波那契序列的分治,效果更差。每层递归只减少一个元素的递归无法降低时间复杂度)!我在纸上大致算了下。递归求解的时间复杂度按如下公式推导:
T(n) = T(n-1) + n*n
这样应该得到:
T(n) = n*n + (n-1)*(n-1) +...+2*2 + 1 = n(n+1)(2n+1)/6
时间复杂度还是O(n*n*n)!!
而且感觉还可以用一个递归来替代上面的一层循环,没时间想了,图书馆要关门了,还要去跑步,明天又要跟导师汇报,暂时先搁一搁吧!忙完了再回来思考下,大家有好的思路的话,希望在下面贴出来!
没想到发生来一天不到,那么多人回复,很感谢大家的热心思考啊!而且看时间有些人是熬夜写的代码啊,不由心生佩服,不过希望要多注意身体哈。
很多人都采用了如下代码来进行优化(我稍微做了些改动,测试通过)
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/*
循环输出子串
*/
void AllSubstring3(const char *str,char *arr)
{
//穿入的arr的长度为len+1,最后一个位置保存'\0'
int i,j;
unsigned int len = strlen(str);
strcpy(arr,str);
for(i=len-1;i>=0;i--)
{
arr[i+1] = '\0';
for(j=i;j>=0;j--)
printf("%s\t",&arr[j]);
printf("\n");
}
}
采用直接打印子串的方法,减少了一个循环,18楼说的在理,这样只是代码间简洁了些,但直接输出字符串和诸葛输出字符效果是一样的,因此复杂度并没有降低。
假设没有重复的情况,连续子串的数目为sum = n + n-1 + n-2 +...+2+1 = n(n-1)/2,但是因为基本的操作是输出单个字符,因此输出次数也就达到了sum*n的级别了,时间复杂度最优貌似也就是O(n*n*n)了,这样看来貌似就没什么可优化的余地喽!!求解。。
再次感谢大家的思考和回复,最近忙死鸟,不能一一细看和回复,望见谅!!
今天下午阿里电面的题目,给定一个字符串,输出其所有连续子串,如:给定字符串为abcd,则要输出的其全部连续子串为:a,b,c,d,ab,bc,cd,abc,bcd,abcd。
很快给出了最简单的方法,就是先从第一个字符遍历,向后输出,再从第二个字符开始遍历,向后输出,依此类推,直到开始遍历的字符为数组的最后一个字符。这个时间复杂度很高啊,要O(n*n*n)。
接下来就假设字符串很大,想优化的方法,不知道脑子是短路了还是咋地,居然联想到Trie树上去了,完全不沾边的东西。电面后想了下,感觉应该用递归,吃完饭,去图书馆用纸画了下,就是递归(还是A题A的少啊!)。后来写出来代码感觉貌似木有提高时间复杂度哦!
先贴出来吧,首先是最简单的遍历法,时间复杂度为O(n*n*n)
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/*
蛮力求解法
*/
void AllSubstring1(const char *str,int high)
{
int i, j, k;
if(!str)
return;
for(i=0;i<=high;i++)
{
for(j=i; j<=high;j++)
{
for(k = i; k<=j; k++)
printf("%c", str[k]);
printf("\t");
}
printf("\n");
}
}
而后我又减少了一层循环,增加了一个递归操作,如下:
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/*
递归求解法
*/
void AllSubstring2(const char *str,int low,int high)
{
int i;
int cur = high;
if(!str)
return;
while(low <= cur)
{
for(i=low;i<=cur;i++)
printf("%c",str[i]);
printf("\t");
cur--;
}
printf("\n");
if(low<high)
{
AllSubstring2(str,low+1,high);
}
}
但是感觉时间复杂度没有提高啊(分治策略的递归代替循环,可以将时间复杂度从O(n)降到O(logn),当然是每次将问题减到一半分治策略,若果是类似斐波那契序列的分治,效果更差。每层递归只减少一个元素的递归无法降低时间复杂度)!我在纸上大致算了下。递归求解的时间复杂度按如下公式推导:
T(n) = T(n-1) + n*n
这样应该得到:
T(n) = n*n + (n-1)*(n-1) +...+2*2 + 1 = n(n+1)(2n+1)/6
时间复杂度还是O(n*n*n)!!
而且感觉还可以用一个递归来替代上面的一层循环,没时间想了,图书馆要关门了,还要去跑步,明天又要跟导师汇报,暂时先搁一搁吧!忙完了再回来思考下,大家有好的思路的话,希望在下面贴出来!
后续
没想到发生来一天不到,那么多人回复,很感谢大家的热心思考啊!而且看时间有些人是熬夜写的代码啊,不由心生佩服,不过希望要多注意身体哈。很多人都采用了如下代码来进行优化(我稍微做了些改动,测试通过)
[cpp] view
plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/*
循环输出子串
*/
void AllSubstring3(const char *str,char *arr)
{
//穿入的arr的长度为len+1,最后一个位置保存'\0'
int i,j;
unsigned int len = strlen(str);
strcpy(arr,str);
for(i=len-1;i>=0;i--)
{
arr[i+1] = '\0';
for(j=i;j>=0;j--)
printf("%s\t",&arr[j]);
printf("\n");
}
}
采用直接打印子串的方法,减少了一个循环,18楼说的在理,这样只是代码间简洁了些,但直接输出字符串和诸葛输出字符效果是一样的,因此复杂度并没有降低。
假设没有重复的情况,连续子串的数目为sum = n + n-1 + n-2 +...+2+1 = n(n-1)/2,但是因为基本的操作是输出单个字符,因此输出次数也就达到了sum*n的级别了,时间复杂度最优貌似也就是O(n*n*n)了,这样看来貌似就没什么可优化的余地喽!!求解。。
再次感谢大家的思考和回复,最近忙死鸟,不能一一细看和回复,望见谅!!
相关文章推荐
- 阿里实习生电面题目:输出给定字符串的全部连续子串
- 阿里实习生电面题目(续):输出给定字符串的全部连续子串
- 阿里实习生电面题目:输出给定字符串的全部连续子串 这是我的感悟
- 阿里实习生电面题目:输出给定字符串的全部连续子串
- 阿里实习生电面题目:输出给定字符串的全部连续子串
- 【算法拾遗】阿里实习生电面题目:输出给定字符串的全部连续子串
- 阿里电面题目:输出给定字符串的全部连续子串
- 阿里电面题:输出给定字符串的全部连续子串
- 算法:输出给定字符串的全部连续子串
- 给定一个字符串s,请计算输出含有连续两个s作为子串的最短字符串。
- 每天学习一点编程(3)(输出给定字串的全部连续子串)
- 给定字符串A和B,输出A和B中的最大公共子串。
- 字符串操作问题:查找给定字符串中,连续重复且长度最长的第一个子串
- 2014阿里巴巴实习生笔试题目
- 题目:剔除一个字符中重复的字符,然后按ASCII码值从小到大排列。 例如,输入:abbcccddeeeffgghh 输出:abcdefgh 注意:1、剔除是整个字符串中重复的字符,而不是连续的字符 2
- 给定字符串A和B,输出A和B中的最大公共子串。
- 2014阿里巴巴实习生笔试题目 .
- 求字符串中由连续的相同字符组成的最长子串(如果有两个及两个以上的最长子串,则输出第二个)
- 字符串处理算法(四)现在一个给定字符串中寻找子串的功能(不能使用库函数)[2014百度笔试题]
- 给定一个字符串,输出最长的重复子串