String 谷歌访谈:寻找字符串之间的疯狂距离
这个问题是在谷歌面试时问我的。我可以做它O(n*n)。。。我能在更好的时间做吗。 字符串只能由1和0组成 定义: X&Y是由0或1组成的字符串String 谷歌访谈:寻找字符串之间的疯狂距离,string,algorithm,String,Algorithm,这个问题是在谷歌面试时问我的。我可以做它O(n*n)。。。我能在更好的时间做吗。 字符串只能由1和0组成 定义: X&Y是由0或1组成的字符串 D(X,Y)=从X和Y两个字符串中删除开始时常见的内容。然后从两个字符串中添加剩余长度 例如 D(11111000)=只有第一个字母是常见的。所以剩下的字符串是111&000。因此,结果length(“111”)和length(“000”)=3+3=6 D(1011100)=只有前两个字母是通用的。所以剩下的字符串是01&100。因此,结果length(
D(X,Y)
=从X和Y两个字符串中删除开始时常见的内容。然后从两个字符串中添加剩余长度
例如
D(11111000)
=只有第一个字母是常见的。所以剩下的字符串是111
&000
。因此,结果length(“111”)
和length(“000”)
=3+3=6
D(1011100)
=只有前两个字母是通用的。所以剩下的字符串是01
&100
。因此,结果length(“01”)
和length(“100”)
=2+3=5
很明显,我们发现这样一个疯狂的距离是线性的。O(m)
现在的问题是
给定n个输入,比如说like
1111
1000
101
1100
找出可能的最大疯狂距离
n是输入字符串的数目。
m是任何输入字符串的最大长度
O(n2*m)的解非常简单。可以用更好的方法吗?
假设m是固定的。我们能用比O(n^2)更好的方法来做这件事吗 将字符串放入树中,其中0表示向左,1表示向右。比如说
1111
1000
101
1100
结果会变成一棵树
Root
1
0 1
0 1* 0 1
0* 0* 1*
其中*表示元素结束于此。构建此树显然需要O(nm)
现在我们必须找到(两个节点之间的最长路径,与“疯狂距离”相同)。这里提出的优化算法只命中树中的每个节点一次。最多有min(n m,2^m)
这样的节点
因此,如果nm<2^m
,则该算法是O(nm)
如果nm>2^m
(我们必须重复输入),那么从第一步开始,算法仍然是O(nm)
这也适用于带有通用字母表的字符串;对于带有
k
字母的字母表,构建一个k
三元树,在这种情况下,运行时间仍然是O(nm),尽管它占用的内存是k
的两倍。我认为,通过创建一个二叉树,字符串中的每一位都对路径(0左,1右)进行编码,在O(nm)时间内就可以做到这一点。然后找到树节点之间的最大距离。这是我的解决方案,我认为它是有效的:
<root>
<1> <empty>
<1> <0>
int max_distance(char** strings, int numstrings, int &distance) {
distance = 0;
// loop O(n) for initialization
for (int i=0; i<numstrings; i++)
distance += strlen(strings[i]);
int max_prefix = 0;
bool done = false;
// loop max O(m)
while (!done) {
int c = -1;
// loop O(n)
for (int i=0; i<numstrings; i++) {
if (strings[i][max_prefix] == 0) {
done = true; // it is enough to reach the end of one string to be done
break;
}
int new_element = strings[i][max_prefix] - '0';
if (-1 == c)
c = new_element;
else {
if (c != new_element) {
done = true; // mismatch
break;
}
}
}
if (!done) {
max_prefix++;
distance -= numstrings;
}
}
return max_prefix;
}
void test_misc() {
char* strings[] = {
"10100",
"10101110",
"101011",
"101"
};
std::cout << std::endl;
int distance = 0;
std::cout << "max_prefix = " << max_distance(strings, sizeof(strings)/sizeof(strings[0]), distance) << std::endl;
}
int max_距离(字符**字符串、int numstrings、int&distance){
距离=0;
//用于初始化的循环O(n)
对于(int i=0;i我认为这个问题类似于“查找两个字符串的前缀”,您可以使用trie()来加速搜索
3天前我有一个谷歌电话面试,但也许我失败了
祝你好运我不知道当迭代给你同样大的O计算复杂度而没有代码复杂度时,为什么要使用树。无论如何,这是我的javascript O(mn)版本
var len=process.argv.length-2;//在节点中,前两个参数是节点和程序文件
var输入=过程argv拼接(2);
无功电流;
var currentCount=0;
var currentCharLoc=0;
var totalCount=0;
var totalComplete=0;
var=true;
while(totalCompletecurrentCharLoc){
currentCount++;
如果(相同){
如果(当前===null){
电流=输入[loc][currentCharLoc];
}否则{
如果(当前!==输入[loc][currentCharLoc]){
相同=错误;
}
}
}
}
}
如果(!相同){
totalCount+=当前计数;
}
currentCharLoc++;
}
console.log(totalCount);
我想我可以对所有的元素进行排序。但即使这样,我也无法在任何地方继续。有谁能指导我解决这个问题的方法吗。@杜克林:谢谢编辑。你能帮我解决这个问题吗?排序也将是算法的一部分。如果列表已排序,那么只需检查连续元素的cra即可zy距离&因此是最大值。然而,我不认为排序是唯一的方法。DoSparKot,你提出的反例:“000”、“001”、“0010”怎么样?按字典顺序对它们进行排序,然后检查连续元素之间的距离,给出D(000001)=len(“0”)+len(“1”)=2,D(0010010010)=len len(”+len(“0”)=1,但D(0000010)=len(“0”)+len(“10”)=3。在这里,我指的是“n”作为字符串的数量。为了找出
var len = process.argv.length -2; // in node first 2 arguments are node and program file
var input = process.argv.splice(2);
var current;
var currentCount = 0;
var currentCharLoc = 0;
var totalCount = 0;
var totalComplete = 0;
var same = true;
while ( totalComplete < len ) {
current = null;
currentCount = 0;
for ( var loc = 0 ; loc < len ; loc++) {
if ( input[loc].length === currentCharLoc) {
totalComplete++;
same = false;
} else if (input[loc].length > currentCharLoc) {
currentCount++;
if (same) {
if ( current === null ) {
current = input[loc][currentCharLoc];
} else {
if (current !== input[loc][currentCharLoc]) {
same = false;
}
}
}
}
}
if (!same) {
totalCount += currentCount;
}
currentCharLoc++;
}
console.log(totalCount);