题目
Write a function to find the longest commonprefix string amongst an array of strings.
找出一系列字符串的公有前缀。
输入是vector<string>&strs。
观察输入,这是一个vector<string>,咋一看是个一维数组。但是,绝大多数情况下,其实里面存的是长短不一的string。因此更像是一个锯齿数组的感觉。
在锯齿数组里面找共有前缀,先不管怎么扫描。有一点可以肯定的是,有些数据是我们不需要扫描的。因为公有前缀,最长,不会比最短的那个string还要长。
因此我们需要扫描的范围,看起来就像是一个规规矩矩的二维数组了。
需要扫描的范围已经被缩减了,至少大部分情况是被缩减了。
接下来,考虑一下怎么扫描了。
第一个思路:纵向扫描,先从头到尾扫描第1个字母,再从头到尾扫描第2个字母,再从头到尾扫描第3个字母……当遇到不相同字符时退出循环,返回公有前缀。
第二个思路:横向扫描,取第一个字符串和第二个字符串的公有前缀作为参照,让它分别于之后的字符串依次取共有前缀,每次取完公有前缀,这个公有前缀便成为新参照,知道最后的那个参照便是最终公有前缀,从执行的过程来看,是横向优先的扫描。这个思路有点类似于等价关系的传递性(a等于b,a等于c。则a等于b等于c。)
简单的评价一下:
仅仅从思路上看,思路2的扫描次数是要比思路1要多的:
1、思路2要多扫描很多次参照前缀,增加了扫描任务;
2、思路1一旦扫描到非公有前缀立即停止扫描得到公有前缀,而思路2一开始的扫描出来的参考,有的可能有多余的字符,并不一定是最终前缀(举个简单的例子,假设共有前缀只是第一个字符,那么思路而必须把除最后一个字符串之外的所有字符串扫描完才会得到结果)。
那么leetcode的提交结果来看,思路1是要比思路2快的。
两个思路一开始就想好了,但是只实现了思路2,因为执行时间紧跟着C语言的,因此就没有再深究,后来在写博客草稿的时候,写着写着,发现从思路上看,思路1应该执行时间更少,后来(2015-06-07)实现了一下思路1,确实如此。
Leetcode的AcceptedSolutions Runtime Distribution(2015-06-07 思路1的提交结果,6ms附近)
(5月上旬。 思路2的提交结果,8ms附近)
源码:(VS2013)如果需要提交leetcode只需要把函数中的代码复制过去即可。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string longest(vector<string>& strs);
int main()
{
vector<string> play;
play.push_back("aca");
play.push_back("aba");
cout << longest(play);
return 0;
}
string longest(vector<string>& strs)
{
//
int size = strs.size();
int minLen;
int i;
//取各字符串中的最短字符串长度。因为公有前缀肯定不会比它长。
for (i = 0; i < size;i++)
{
int len = strs[i].size();
if (0 == i) minLen = len;
else if (len < minLen) minLen = len;
}
//如果有一个空字符串,那么公有前缀肯定为空。
if (0 == minLen || 0 == size ) return "";
//以上部分是两个思路共用的代码
//需注意[]操作符需要自己判断越界,相对的,速度上比at()要有优势。
/*
//这里是思路2
vector<string>::iterator iter = strs.begin();//auto
int resLen = minLen;
string s1 = strs[0];
while (iter != strs.end())
{
int tempLen = 0;
for (i = 0; i < minLen; i++)
{
if (s1[i] == (*iter)[i]) tempLen++;
else break;
}
if (tempLen < resLen) resLen = tempLen;
iter++;
}
return s1.substr(0, resLen);
*/
//
//这里是思路1
vector<string>::iterator iter = strs.begin();//auto
string res = "";
int index = 0;
char temp = (*iter)[index];
while (strs.end() != iter)
{
if (temp != (*iter)[index]) break;
iter++;
if (strs.end() == iter)
{
iter = strs.begin();
index++;
res += temp;
if (index >= minLen) break;
temp = (*iter)[index];
}
}
return res;
}