¡Awww! Una gran cantidad de aportes brillantes. Tomaré uno para resolver mi problema en cuestión, pero creo que para elegir realmente una respuesta aceptada justificada, tendré que comparar las soluciones. Puede tomar un tiempo hasta que lo haga, pero ciertamente lo haré.
– Peka
19 de julio de 2010 a las 12:39
título entretenido 😀 por cierto: ¿por qué no puedo encontrarte en la lista de moderadores nominados? @Pekka
– El Surricano
19 de enero de 2011 a las 16:38
ninguna respuesta aceptada durante dos años?
– Gordon
18 de junio de 2012 a las 19:44
@Pekka Acercándonos a los tres años desde que esto no tiene una respuesta aceptada 🙁 Y es un título tan increíble que lo recordé hace un momento y busqué en Google “tetrising an array”.
– Camilo Martín
19 de abril de 2013 a las 13:26
escribir una función longest_common_prefix que toma dos cadenas como entrada. Luego aplíquelo a las cadenas en cualquier orden para reducirlas a su prefijo común. Como es asociativo y conmutativo, el orden no importa para el resultado.
Esto es lo mismo que para otras operaciones binarias como, por ejemplo, la suma o el máximo común divisor.
+1. Después de comparar las 2 primeras cadenas, utilice el resultado (ruta común) para comparar con la 3.ª cadena y así sucesivamente.
– Milan Babuškov
18 de julio de 2010 a las 15:20
fanfarrón
Cárguelos en una estructura de datos trie. Comenzando desde el nodo principal, vea cuál tiene un hijo que cuenta más que uno. Una vez que encuentre ese nodo mágico, simplemente desmantele la estructura del nodo principal y tenga el nodo actual como raíz.
¿La operación que carga los datos en la estructura de árbol trie que describe no incluiría un poco el algoritmo para encontrar el prefijo común más largo, haciendo así innecesario el uso de una estructura de árbol? Es decir, ¿por qué revisar el árbol en busca de varios niños cuando podría detectarlo mientras construye el árbol? ¿Por qué entonces un árbol en absoluto? Quiero decir, si ya comienzas con una matriz. Si puede cambiar el almacenamiento para usar solo un trie en lugar de matrices, supongo que tiene sentido.
– Ben Schwehn
18 de julio de 2010 a las 15:21
Creo que si tiene cuidado, mi solución es más eficiente que construir un trie.
– estrella azul
24 de julio de 2010 a las 19:50
Esta respuesta es incorrecta. Hay soluciones triviales publicadas en my y otras respuestas que son O (n).
– Ari Ronen
8 de agosto de 2010 a las 6:06
@el.pescado: Los intentos son de tamaño cuadrático con la longitud de la cadena de origen en el peor de los casos.
Esta es, con mucho, la mejor solución publicada, pero necesitaba mejoras. No tomó en cuenta la ruta común más larga anterior (posiblemente iterando sobre más de la cadena de lo necesario) y no tomó en cuenta las rutas (así que para /usr/lib y /usr/lib2 lo dio /usr/lib como el camino común más largo, en lugar de /usr/). Yo (con suerte) arreglé ambos.
– Gabo
18 de julio de 2010 a las 15:41
ircmaxell
Bueno, considerando que puedes usar XOR en esta situación para encontrar las partes comunes de la cadena. Cada vez que xor dos bytes que son iguales, obtiene un byte nulo como salida. Entonces podemos usar eso a nuestro favor:
Después de ese bucle único, el $length variable será igual a la parte base común más larga entre la matriz de cadenas. Entonces, podemos extraer la parte común del primer elemento:
Tenga en cuenta que usa más de una iteración, pero esas iteraciones se realizan en bibliotecas, por lo que en lenguajes interpretados esto tendrá una gran ganancia de eficiencia…
Ahora, si solo desea rutas completas, debemos truncar hasta el último / personaje. Asi que:
Ahora, puede cortar demasiado dos hilos como /foo/bar y /foo/bar/baz será cortado a /foo. Pero antes de agregar otra ronda de iteración para determinar si el siguiente carácter es /o final de cadena, no puedo ver una forma de evitar eso …
Félix Kling
Un enfoque ingenuo sería explotar los caminos en el / y comparar sucesivamente cada elemento en las matrices. Entonces, por ejemplo, el primer elemento estaría vacío en todas las matrices, por lo que se eliminará, el siguiente elemento será wwwes el mismo en todas las matrices, por lo que se elimina, etc.
Algo como (no probado)
$exploded_paths = array();
foreach($paths as $path) {
$exploded_paths[] = explode("https://stackoverflow.com/", $path);
}
$equal = true;
$ref = &$exploded_paths[0]; // compare against the first path for simplicity
while($equal) {
foreach($exploded_paths as $path_parts) {
if($path_parts[0] !== $ref[0]) {
$equal = false;
break;
}
}
if($equal) {
foreach($exploded_paths as &$path_parts) {
array_shift($path_parts); // remove the first element
}
}
}
Después solo tienes que implosionar los elementos en $exploded_paths otra vez:
Esto tomará el primer valor en la matriz como cadena de referencia. Luego iterará sobre la cadena de referencia y comparará cada carácter con el carácter de la segunda cadena en la misma posición. Si un carácter no coincide, la cadena de referencia se acortará a la posición del carácter y se comparará la siguiente cadena. La función devolverá la cadena coincidente más corta entonces.
El rendimiento depende de las cadenas dadas. Cuanto antes se acorte la cadena de referencia, más rápido terminará el código. Sin embargo, realmente no tengo ni idea de cómo poner eso en una fórmula.
Descubrí que el enfoque de Artefacto para ordenar las cadenas aumenta el rendimiento. agregando
antes de array_reduce aumentará significativamente el rendimiento.
También tenga en cuenta que esto devolverá el subcadena inicial coincidente más largaque es más versátil pero no te dará la camino común. tienes que correr
Puede eliminar el prefijo de la manera más rápida, leyendo cada carácter solo una vez:
function findLongestWord($lines, $delim = "https://stackoverflow.com/")
{
$max = 0;
$len = strlen($lines[0]);
// read first string once
for($i = 0; $i < $len; $i++) {
for($n = 1; $n < count($lines); $n++) {
if($lines[0][$i] != $lines[$n][$i]) {
// we've found a difference between current token
// stop search:
return $max;
}
}
if($lines[0][$i] == $delim) {
// we've found a complete token:
$max = $i + 1;
}
}
return $max;
}
$max = findLongestWord($lines);
// cut prefix of len "max"
for($n = 0; $n < count($lines); $n++) {
$lines[$n] = substr(lines[$n], $max, $len);
}
De hecho, una comparación basada en caracteres será la más rápida. Todas las demás soluciones usan operadores “caros” que al final también harán (múltiples) comparaciones de caracteres. Incluso fue mencionado en las escrituras del Santo Joel.!
– Jan Fabry
9 de agosto de 2010 a las 7:03
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
Esto podría valer la pena intentarlo: en.wikibooks.org/wiki/Algorithm_implementation/Strings/… (Lo probé y funciona).
– Richard Knop
19 de julio de 2010 a las 9:05
¡Awww! Una gran cantidad de aportes brillantes. Tomaré uno para resolver mi problema en cuestión, pero creo que para elegir realmente una respuesta aceptada justificada, tendré que comparar las soluciones. Puede tomar un tiempo hasta que lo haga, pero ciertamente lo haré.
– Peka
19 de julio de 2010 a las 12:39
título entretenido 😀 por cierto: ¿por qué no puedo encontrarte en la lista de moderadores nominados? @Pekka
– El Surricano
19 de enero de 2011 a las 16:38
ninguna respuesta aceptada durante dos años?
– Gordon
18 de junio de 2012 a las 19:44
@Pekka Acercándonos a los tres años desde que esto no tiene una respuesta aceptada 🙁 Y es un título tan increíble que lo recordé hace un momento y busqué en Google “tetrising an array”.
– Camilo Martín
19 de abril de 2013 a las 13:26