Una nota sobre metodología
Pensé un poco en este problema y llegué a una solución. Cuando leí la respuesta de Saeed Amiri , me di cuenta de que se me ocurrió una versión especializada del algoritmo estándar de búsqueda de subsecuencias más largo para una secuencia de longitud 3. Estoy publicando la forma en que se me ocurrió la solución, porque creo que Es un ejemplo interesante de resolución de problemas.
La versión de dos elementos.
Comencemos con algo pequeño: en lugar de buscar tres índices en los que los elementos estén en orden, busquemos dos: tal que A [ i ] < A [ j ] .i < jA [ i ] < A [ j ]
Si está disminuyendo (es decir, ∀ i < j , A [ i ] ≥ A [ j ] , o de manera equivalente ∀ i , A [ i ] ≥ A [ i + 1 ] , entonces no existen tales índices. De lo contrario, hay un índice i tal que A [ i ] < A [ i + 1 ] .UNA∀ i < j , A [ i ] ≥ A [ j ]∀ i , A [ i ] ≥ A [ i + 1 ]yoA [ i ] < A [ i + 1 ]
Este caso es muy simple; Intentaremos generalizarlo. Muestra que el problema tal como se indicó no tiene solución: los índices solicitados no siempre existen. Por lo tanto, pediremos más bien que el algoritmo devuelva índices válidos, si existen, o afirme correctamente que no existen tales índices.
Subiendo con el algoritmo
Usaré el término subsecuencia para significar un extracto de la matriz consiste en índices que pueden no ser consecutivos ( ( A [ i 1 ] , … , A [ i m ] ) con i 1 < ⋯ < i m ), y ejecutaré significa elementos consecutivos de A ( ( A [ i ] , A [ i + 1 ] , … , A [UNA( A [ i1] , ... , A [ imetro] )yo1< ⋯ < imetroUNA ).(A[i],A[i+1],…,A[i+m−1])
Acabamos de ver que los índices solicitados no siempre existen. Nuestra estrategia será estudiar cuando los índices no existen. Haremos esto suponiendo que estamos tratando de encontrar los índices y viendo cómo nuestra búsqueda podría salir mal. Entonces, los casos en los que la búsqueda no sale mal proporcionarán un algoritmo para encontrar los índices.
Con dos índices, podríamos encontrar índices consecutivos. Con tres índices, es posible que no podamos encontrar y k = j + 1 . Sin embargo, podemos considerar el caso cuando hay una serie de tres elementos estrictamente crecientes ( A [ i ] < A [ i + 1 ] < A [ i + 2 ] ) por resolver, ya que es fácil reconocer tales series, y vea cómo esta condición podría no cumplirse. Suponga que la secuencia no tiene una ejecución estrictamente creciente de longitud 3.j = i + 1k = j + 1A [ i ] < A [ i + 1 ] < A [ i + 2 ]
La secuencia solo tiene carreras estrictamente crecientes de longitud 2 (que llamaré pares ordenados para abreviar), separadas por una carrera decreciente de longitud al menos 2. Para una carrera estrictamente creciente para formar parte de una secuencia creciente de 3 elementos, debe haber un elemento anterior i tal que A [ i ] < A [ j ] o un elemento posterior k tal que A [ j + 1 ] < A [ kA [ j ] < A [ j + 1 ]yoA [ i ] < A [ j ]k .A [ j + 1 ] < A [ k ]
Un caso en el que ni ni k existe es cuando cada par ordenado es completamente inferior al siguiente. Esto no es todo: cuando los pares están entrelazados, necesitamos compararlos más finamente.yok
El elemento más a la izquierda de una subsecuencia creciente necesita llegar temprano y ser pequeño. El siguiente elemento j debe ser más grande, pero lo más pequeño posible para poder encontrar un tercer elemento más grande k . El primer elemento i no siempre es el elemento más pequeño de la secuencia, y tampoco es siempre el primero para el que hay un elemento posterior más grande, a veces hay una subsecuencia inferior de 2 elementos más adelante, y a veces hay una mejor apto para el mínimo ya encontrado.yojkyo
yo( i , j )kyo( i , j )( i , j )yo′> jA [ i′] < A [ i ]yo′yo( i , j )j′A [ j′] < A [ j ]( i′, j′)
Declaración del algoritmo
Dado en la sintaxis de Python, pero tenga en cuenta que no lo he probado.
def subsequence3(A):
"""Return the indices of a subsequence of length 3, or None if there is none."""
index1 = None; value1 = None
index2 = None; value2 = None
for i in range(0,len(A)):
if index1 == None or A[i] < value1:
index1 = i; value1 = A[i]
else if A[i] == value1: pass
else if index2 == None:
index2 = (index1, i); value2 = (value1, A[i])
else if A[i] < value2[1]:
index2[1] = i; value2[1] = A[i]
else if A[i] > value2[1]:
return (index2[0], index2[1], i)
return None
Bosquejo de prueba
index1
es el índice del mínimo de la parte de la matriz que ya se ha atravesado (si ocurre varias veces, conservamos la primera aparición) o None
antes de procesar el primer elemento. index2
almacena los índices de la subsecuencia creciente de longitud 2 en la parte ya atravesada de la matriz que tiene el elemento más grande más bajo, o None
si tal secuencia no existe.
Cuando se return (index2[0], index2[1], i)
ejecuta, tenemos value2[0] < value[1]
(esto es una invariante de value2
) y value[1] < A[i]
(obvio por el contexto). Si el ciclo termina sin invocar el retorno temprano, tampoco value1 == None
, en cuyo caso no hay subsecuencia creciente de longitud 2 y mucho menos 3, o value1
contiene la subsecuencia creciente de longitud 2 que tiene el elemento más grande más bajo. En el último caso, además tenemos la invariante de que ninguna subsecuencia creciente de longitud 3 termina antes que value1
; por lo tanto, el último elemento de cualquiera de esas subsecuencias, sumado a value2
, formaría una subsecuencia creciente de longitud 3: como también tenemos el invariante que value2
no es parte de una subsecuencia creciente de longitud 3 contenida en la parte ya atravesada de la matriz, allí no existe tal subsecuencia en toda la matriz.
Probar los invariantes antes mencionados se deja como un ejercicio para el lector.
Complejidad
O ( 1 )O ( 1 )O ( n )
Prueba formal
A la izquierda como ejercicio para el lector.