谷歌访谈:找到字符串之间的疯狂距离

时间:2013-02-25 07:20:12

标签: string algorithm

谷歌采访时向我询问了这个问题。我能做到O(n * n)......我可以在更好的时间做到这一点。 字符串只能由1和0组成。

定义:

X& Y是由0或1

形成的字符串

D(X,Y) =从X&删除开头常见的东西是。然后从两个字符串中添加剩余的长度。

例如

D(1111, 1000) =只有第一个字母是常见的。所以剩下的字符串是111& 000。因此结果为length("111")& length("000") = 3 + 3 = 6

D(101, 1100) =只有前两个字母很常见。所以剩下的字符串是01& 100。因此结果为length("01")& length("100") = 2 + 3 = 5

很明显,确实发现这样一个疯狂的距离将是线性的。 O(M)。

现在的问题是

给出n输入,比如说

1111
1000
101
1100

找出可能的最大疯狂距离。

n是输入字符串的数量。 m是任何输入字符串的最大长度。

O(n 2 * m)的解非常简单。它能以更好的方式完成吗? 我们假设m是固定的。我们能比O(n ^ 2)做得更好吗?

6 个答案:

答案 0 :(得分:21)

将字符串放入树中,其中0表示向左移动,1表示向右移动。例如,

1111
1000
101
1100

会产生类似

的树
        Root
             1
          0     1
         0 1*  0  1
        0*    0*    1*

其中*表示元素在那里结束。构建这棵树显然需要O(n m)

现在我们必须找到diameter of the tree(两个节点之间的最长路径,这与“疯狂距离”相同)。在那里呈现的优化算法命中树中的每个节点一次。最多有min(n m, 2^m)个此类节点。

因此,如果n m < 2^m,则算法为O(n m)

如果n m > 2^m(我们必须重复输入),那么从第一步开始算法仍为O(n m)

这也适用于具有通用字母表的字符串;对于带有k字母的字母表构建一个k - ary树,在这种情况下,运行时仍然是O(nm)相同的推理,尽管它需要k倍的内存。

答案 1 :(得分:4)

我认为这可以在O(nm)时间内通过创建二进制树来实现,其中字符串中的每个位对路径进行编码(0左,1右)。然后找到树which can be done in O(n) time的节点之间的最大距离。

答案 2 :(得分:1)

这是我的解决方案,我认为它有效:

  1. 从所有字符串创建二叉树。树将以这种方式构建: 在每一轮中,选择一个字符串并将其添加到树中。所以对于你的例子,树将是:

                      <root>
              <1>            <empty>
     <1>            <0>
    

    &LT 1为卤素; &℃,GT; &LT 1为卤素; &℃,GT; &LT 1为卤素; &℃,GT; &℃,GT;

  2. 因此从根到叶子的每条路径都代表一个字符串。

    1. 现在每两片叶子之间的距离是两根弦之间的距离。要找到疯狂的距离,您必须找到此图表的直径,您可以通过dfs或bfs轻松完成。
    2. 此算法的总体复杂性为: O(n * m)+ O(n * m)= O(n * m)。

答案 3 :(得分:0)

要在O(nm)中得到答案,只需迭代所有字符串的字符(这是一个O(n)操作)。我们将比较最多m个字符,因此这将完成O(m)。这给出总共O(nm)。这是一个C ++解决方案:

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;
}

答案 4 :(得分:0)

我认为这个问题类似于&#34;找到两个字符串的前缀&#34;,你可以使用trie(http://en.wikipedia.org/wiki/Trie)来识别搜索

我在3天前接受了谷歌电话采访,但也许我失败了......

祝你好运

答案 5 :(得分:0)

不确定为什么在迭代时使用树会在没有代码复杂性的情况下为您提供相同的大O计算复杂度。无论如何这里是我在javascript O(mn)

的版本
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);