Un algoritmo en el lugar para la transformación de strings

Dada una string, mueva todos los elementos colocados pares al final de la string. Mientras mueve elementos, mantenga el mismo orden relativo de todos los elementos en posiciones pares e impares. Por ejemplo, si la string dada es «a1b2c3d4e5f6g7h8i9j1k2l3m4», conviértala en «abcdefghijklm1234567891234» en el lugar y en complejidad de tiempo O(n).

A continuación se muestran los pasos:

  1. Recorte la substring de prefijo más grande del tamaño de la forma 3^k + 1. En este paso, encontramos el entero no negativo más grande k tal que 3^k+1 es menor o igual que n (longitud de la cuerda)
  2. Aplique el algoritmo de iteración del líder del ciclo (se ha discutido a continuación), comenzando con el índice 1, 3, 9…… a esta substring. El algoritmo de iteración del líder del ciclo mueve todos los elementos de esta substring a sus posiciones correctas, es decir, todos los alfabetos se desplazan a la mitad izquierda de la substring y todos los dígitos se desplazan a la mitad derecha de esta substring.
  3. Procese la substring restante de forma recursiva utilizando los pasos n.° 1 y n.° 2.
  4. Ahora, solo necesitamos unir las substrings procesadas. Comience desde cualquier extremo (por ejemplo, desde la izquierda), elija dos substrings y aplique los pasos a continuación:
    …. 4.1 Invierta la segunda mitad de la primera substring. 
    …. 4.2 Invierta la primera mitad de la segunda substring. 
    …. 4.3 Invierta la segunda mitad de la primera substring y la primera mitad de la segunda substring juntas.
  5. Repita el paso 4 hasta que se unan todas las substrings. Es similar a la fusión de k-way donde la primera substring se une con la segunda. La resultante se fusiona con la tercera y así sucesivamente.

Entendámoslo con un ejemplo:

Tenga en cuenta que hemos utilizado valores como 10, 11 12 en el siguiente ejemplo. Considere estos valores solo como caracteres individuales. Estos valores se utilizan para mejorar la legibilidad.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
a 1 b 2 c 3 d 4 e 5 f  6  g  7  h  8  i  9  j  10 k  11 l  12 m  13

Después de dividirse en el tamaño de la forma 3^k + 1, se forman dos substrings de tamaño 10 cada una. La tercera substring está formada por el tamaño 4 y la cuarta substring está formada por el tamaño 2.

0 1 2 3 4 5 6 7 8 9         
a 1 b 2 c 3 d 4 e 5         

10 11 12 13 14 15 16 17 18 19          
f  6  g  7  h  8  i  9  j  10           

20 21 22 23 
k  11 l  12 

24 25
m  13

Después de aplicar el algoritmo de iteración del líder del ciclo a la primera substring:

0 1 2 3 4 5 6 7 8 9          
a b c d e 1 2 3 4 5          

10 11 12 13 14 15 16 17 18 19          
f  6  g  7  h  8  i  9  j  10 

20 21 22 23 
k  11 l  12 

24 25
m  13

Después de aplicar el algoritmo de iteración del líder del ciclo a la segunda substring:

0 1 2 3 4 5 6 7 8 9          
a b c d e 1 2 3 4 5          

10 11 12 13 14 15 16 17 18 19           
f  g  h  i  j  6  7  8  9  10 

20 21 22 23 
k  11 l  12 

24 25
m 13

Después de aplicar el algoritmo de iteración del líder del ciclo a la tercera substring:

0 1 2 3 4 5 6 7 8 9          
a b c d e 1 2 3 4 5          

10 11 12 13 14 15 16 17 18 19            
f  g  h  i  j  6  7  8  9  10

20 21 22 23 
k  l  11 12 

24 25
m  13

Después de aplicar el algoritmo de iteración del líder del ciclo a la cuarta substring:

0 1 2 3 4 5 6 7 8 9  
a b c d e 1 2 3 4 5  

10 11 12 13 14 15 16 17 18 19             
f  g  h  i  j  6  7  8  9  10   

20 21 22 23 
k  l  11 12 

24 25
m  13

Unión de la primera substring y la segunda substring: 
1. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten.

0 1 2 3 4 5 6 7 8 9          
a b c d e 5 4 3 2 1            <--------- First Sub-string  

10 11 12 13 14 15 16 17 18 19             
j  i  h  g  f  6  7  8  9  10  <--------- Second Sub-string  

20 21 22 23 
k  l  11 12 

24 25
m  13

2. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten juntas (están fusionadas, es decir, ahora solo hay tres substrings).

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
a b c d e f g h i j 1  2  3  4  5  6  7  8  9  10

20 21 22 23 
k  l  11 12 

24 25
m  13

Unión de la primera substring y la segunda substring: 
1. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
a b c d e f g h i j 10 9  8  7  6  5  4  3  2  1 <--------- First Sub-string  

20 21 22 23 
l  k  11 12                                      <--------- Second Sub-string

24 25
m  13

2. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten juntas (están fusionadas, es decir, ahora solo hay dos substrings).

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  
a b c d e f g h i j k  l  1  2  3  4  5  6  7  8  9  10 11 12  

24 25
m  13 

Unión de la primera substring y la segunda substring: 
1. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
a b c d e f g h i j k  l  12 11 10 9  8  7  6  5  4  3  2  1 <----- First Sub-string

24 25
m  13   <----- Second Sub-string 

2. La segunda mitad de la primera substring y la primera mitad de la segunda substring se invierten juntas (están fusionadas, es decir, ahora solo hay una substring).

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
a b c d e f g h i j k  l  m  1  2  3  4  5  6  7  8  9  10 11 12 13

Dado que todas las substrings se han unido, hemos terminado.

¿Cómo funciona el algoritmo de iteración del líder del ciclo?
Entendámoslo con un ejemplo: 

Input:
0 1 2 3 4 5 6 7 8 9
a 1 b 2 c 3 d 4 e 5

Output:
0 1 2 3 4 5 6 7 8 9 
a b c d e 1 2 3 4 5

Old index    New index
0        0
1        5
2        1
3        6
4        2
5        7
6        3
7        8
8        4
9        9

Sea len la longitud de la cuerda. Si observamos cuidadosamente, encontramos que el nuevo índice viene dado por la siguiente fórmula: 

if( oldIndex is odd )
    newIndex = len / 2 + oldIndex / 2;
else
        newIndex = oldIndex / 2;

Entonces, el problema se reduce a cambiar los elementos a nuevos índices basados ​​en la fórmula anterior.
El algoritmo de iteración del líder del ciclo se aplicará a partir de los índices de la forma 3^k, comenzando con k = 0.

A continuación se muestran los pasos:

  1. Encuentre una nueva posición para el elemento en la posición i. Antes de colocar este elemento en la nueva posición, mantenga la copia de seguridad del elemento en la nueva posición. Ahora, coloque el elemento en la nueva posición.
  2. Repita el paso 1 para la nueva posición hasta que se complete un ciclo, es decir, hasta que el procedimiento vuelva a la posición inicial.
  3. Aplique el algoritmo de iteración del líder del ciclo al siguiente índice de la forma 3^k. Repita este paso hasta que 3^k < len. 
Consider input array of size 28:
The first cycle leader iteration, starting with index 1:
1->14->7->17->22->11->19->23->25->26->13->20->10->5->16->8->4->2->1
The second cycle leader iteration, starting with index 3:
3->15->21->24->12->6->3
The third cycle leader iteration, starting with index 9:
9->18->9

Basado en el algoritmo anterior, a continuación se muestra el código:  

C++

// C++ implementation of above approach
#include <bits/stdc++.h>
using namespace std;
 
// A utility function to swap characters
void swap ( char* a, char* b )
{
    char t = *a;
    *a = *b;
    *b = t;
}
 
// A utility function to reverse string str[low..high]
void reverse ( char* str, int low, int high )
{
    while ( low < high )
    {
        swap( &str[low], &str[high] );
        ++low;
        --high;
    }
}
 
// Cycle leader algorithm to move all even
//  positioned elements at the end.
void cycleLeader ( char* str, int shift, int len )
{
    int j;
    char item;
 
    for (int i = 1; i < len; i *= 3 )
    {
        j = i;
 
        item = str[j + shift];
        do
        {
            // odd index
            if ( j & 1 )
                j = len / 2 + j / 2;
            // even index
            else
                j /= 2;
 
            // keep the back-up of element at new position
            swap (&str[j + shift], &item);
        }
        while ( j != i );
    }
}
 
// The main function to transform a string. This function 
// mainly uses cycleLeader() to transform
void moveNumberToSecondHalf( char* str )
{
    int k, lenFirst;
 
    int lenRemaining = strlen( str );
    int shift = 0;
 
    while ( lenRemaining )
    {
        k = 0;
 
        // Step 1: Find the largest prefix
        // subarray of the form 3^k + 1
        while ( pow( 3, k ) + 1 <= lenRemaining )
            k++;
        lenFirst = pow( 3, k - 1 ) + 1;
        lenRemaining -= lenFirst;
 
        // Step 2: Apply cycle leader algorithm
        // for the largest subarrau
        cycleLeader ( str, shift, lenFirst );
 
        // Step 4.1: Reverse the second half of first subarray
        reverse ( str, shift / 2, shift - 1 );
 
        // Step 4.2: Reverse the first half of second sub-string.
        reverse ( str, shift, shift + lenFirst / 2 - 1 );
 
        // Step 4.3 Reverse the second half of first sub-string
        // and first half of second sub-string together
        reverse ( str, shift / 2, shift + lenFirst / 2 - 1 );
 
        // Increase the length of first subarray
        shift += lenFirst;
    }
}
 
// Driver program to test above function
int main()
{
    char str[] = "a1b2c3d4e5f6g7";
    moveNumberToSecondHalf( str );
    cout<<str;
    return 0;
}
 
// This is code is contributed by rathbhupendra

Java

// Java implementation of above approach
import java.util.*;
 
class GFG{
     
static char []str;
 
// A utility function to reverse
// String str[low..high]
static void reverse(int low, int high)
{
    while (low < high)
    {
        char t = str[low];
        str[low] = str[high];
        str[high] = t;
        ++low;
        --high;
    }
}
 
// Cycle leader algorithm to move all even
// positioned elements at the end.
static void cycleLeader(int shift, int len)
{
    int j;
    char item;
 
    for(int i = 1; i < len; i *= 3)
    {
        j = i;
        item = str[j + shift];
         
        do
        {
             
            // odd index
            if (j % 2 == 1)
                j = len / 2 + j / 2;
                 
            // even index
            else
                j /= 2;
 
            // Keep the back-up of element at
            // new position
            char t = str[j + shift];
            str[j + shift] = item;
            item = t;
        }
        while (j != i);
    }
}
 
// The main function to transform a String.
// This function mainly uses cycleLeader()
// to transform
static void moveNumberToSecondHalf()
{
    int k, lenFirst;
    int lenRemaining = str.length;
    int shift = 0;
 
    while (lenRemaining > 0)
    {
        k = 0;
 
        // Step 1: Find the largest prefix
        // subarray of the form 3^k + 1
        while (Math.pow(3, k) + 1 <= lenRemaining)
            k++;
             
        lenFirst = (int)Math.pow(3, k - 1) + 1;
        lenRemaining -= lenFirst;
 
        // Step 2: Apply cycle leader algorithm
        // for the largest subarrau
        cycleLeader(shift, lenFirst);
 
        // Step 4.1: Reverse the second half
        // of first subarray
        reverse(shift / 2, shift - 1);
 
        // Step 4.2: Reverse the first half
        // of second sub-String.
        reverse(shift, shift + lenFirst / 2 - 1);
 
        // Step 4.3 Reverse the second half
        // of first sub-String and first half
        // of second sub-String together
        reverse(shift / 2, shift + lenFirst / 2 - 1);
 
        // Increase the length of first subarray
        shift += lenFirst;
    }
}
 
// Driver code
public static void main(String[] args)
{
    String st = "a1b2c3d4e5f6g7";
    str = st.toCharArray();
     
    moveNumberToSecondHalf();
     
    System.out.print(str);
}
}
 
// This code is contributed by Princi Singh

Python3

# Python implementation of above approach
 
# A utility function to reverse string str[low..high]
def Reverse(string: list, low: int, high: int):
    while low < high:
        string[low], string[high] = string[high], string[low]
        low += 1
        high -= 1
 
# Cycle leader algorithm to move all even
# positioned elements at the end.
def cycleLeader(string: list, shift: int, len: int):
    i = 1
    while i < len:
        j = i
        item = string[j + shift]
 
        while True:
 
            # odd index
            if j & 1:
                j = len // 2 + j // 2
 
            # even index
            else:
                j //= 2
 
            # keep the back-up of element at new position
            string[j + shift], item = item, string[j + shift]
 
            if j == i:
                break
        i *= 3
 
# The main function to transform a string. This function
# mainly uses cycleLeader() to transform
def moveNumberToSecondHalf(string: list):
    k, lenFirst = 0, 0
    lenRemaining = len(string)
    shift = 0
 
    while lenRemaining:
        k = 0
 
        # Step 1: Find the largest prefix
        # subarray of the form 3^k + 1
        while pow(3, k) + 1 <= lenRemaining:
            k += 1
        lenFirst = pow(3, k - 1) + 1
        lenRemaining -= lenFirst
 
        # Step 2: Apply cycle leader algorithm
        # for the largest subarrau
        cycleLeader(string, shift, lenFirst)
 
        # Step 4.1: Reverse the second half of first subarray
        Reverse(string, shift // 2, shift - 1)
 
        # Step 4.2: Reverse the first half of second sub-string
        Reverse(string, shift, shift + lenFirst // 2 - 1)
 
        # Step 4.3 Reverse the second half of first sub-string
        # and first half of second sub-string together
        Reverse(string, shift // 2, shift + lenFirst // 2 - 1)
 
        # Increase the length of first subarray
        shift += lenFirst
 
# Driver Code
if __name__ == "__main__":
 
    string = "a1b2c3d4e5f6g7"
    string = list(string)
    moveNumberToSecondHalf(string)
    print(''.join(string))
 
# This code is contributed by
# sanjeev2552

C#

// C# implementation of
// the above approach
using System;
class GFG{
     
static char []str;
 
// A utility function to
// reverse String str[low
// ..high]
static void reverse(int low,
                    int high)
{
  while (low < high)
  {
    char t = str[low];
    str[low] = str[high];
    str[high] = t;
    ++low;
    --high;
  }
}
 
// Cycle leader algorithm to
// move all even positioned
// elements at the end.
static void cycleLeader(int shift,
                        int len)
{
  int j;
  char item;
 
  for(int i = 1;
          i < len; i *= 3)
  {
    j = i;
    item = str[j + shift];
 
    do
    {
      // odd index
      if (j % 2 == 1)
        j = len / 2 + j / 2;
 
      // even index
      else
        j /= 2;
 
      // Keep the back-up of
      // element at new position
      char t = str[j + shift];
      str[j + shift] = item;
      item = t;
    }
    while (j != i);
  }
}
 
// The main function to transform
// a String. This function mainly
// uses cycleLeader() to transform
static void moveNumberToSecondHalf()
{
  int k, lenFirst;
  int lenRemaining = str.Length;
  int shift = 0;
 
  while (lenRemaining > 0)
  {
    k = 0;
 
    // Step 1: Find the largest prefix
    // subarray of the form 3^k + 1
    while (Math.Pow(3, k) +
           1 <= lenRemaining)
      k++;
 
    lenFirst = (int)Math.Pow(3,
                             k - 1) + 1;
    lenRemaining -= lenFirst;
 
    // Step 2: Apply cycle leader
    // algorithm for the largest
    // subarrau
    cycleLeader(shift, lenFirst);
 
    // Step 4.1: Reverse the second
    // half of first subarray
    reverse(shift / 2,
            shift - 1);
 
    // Step 4.2: Reverse the
    // first half of second
    // sub-String.
    reverse(shift, shift +
            lenFirst / 2 - 1);
 
    // Step 4.3 Reverse the second
    // half of first sub-String and
    // first half of second sub-String
    // together
    reverse(shift / 2, shift +
            lenFirst / 2 - 1);
 
    // Increase the length of
    // first subarray
    shift += lenFirst;
  }
}
 
// Driver code
public static void Main(String[] args)
{
  String st = "a1b2c3d4e5f6g7";
  str = st.ToCharArray();
  moveNumberToSecondHalf();
  Console.Write(str);
}
}
 
// This code is contributed by 29AjayKumar

Javascript

<script>
// Javascript implementation of above approach
 
let str;
 
// A utility function to reverse
// String str[low..high]
function reverse(low,high)
{
    while (low < high)
    {
        let t = str[low];
        str[low] = str[high];
        str[high] = t;
        ++low;
        --high;
    }
}
 
// Cycle leader algorithm to move all even
// positioned elements at the end.
function cycleLeader(shift,len)
{
    let j;
    let item;
  
    for(let i = 1; i < len; i *= 3)
    {
        j = i;
        item = str[j + shift];
          
        do
        {
              
            // odd index
            if (j % 2 == 1)
                j = Math.floor(len / 2) + Math.floor(j / 2);
                  
            // even index
            else
                j =Math.floor(j/2);
  
            // Keep the back-up of element at
            // new position
            let t = str[j + shift];
            str[j + shift] = item;
            item = t;
        }
        while (j != i);
    }
}
 
// The main function to transform a String.
// This function mainly uses cycleLeader()
// to transform
function moveNumberToSecondHalf()
{
    let k, lenFirst;
    let lenRemaining = str.length;
    let shift = 0;
  
    while (lenRemaining > 0)
    {
        k = 0;
  
        // Step 1: Find the largest prefix
        // subarray of the form 3^k + 1
        while (Math.pow(3, k) + 1 <= lenRemaining)
            k++;
              
        lenFirst = Math.floor(Math.pow(3, k - 1)) + 1;
        lenRemaining -= lenFirst;
  
        // Step 2: Apply cycle leader algorithm
        // for the largest subarrau
        cycleLeader(shift, lenFirst);
  
        // Step 4.1: Reverse the second half
        // of first subarray
        reverse(Math.floor(shift / 2), shift - 1);
  
        // Step 4.2: Reverse the first half
        // of second sub-String.
        reverse(shift, shift + Math.floor(lenFirst / 2) - 1);
  
        // Step 4.3 Reverse the second half
        // of first sub-String and first half
        // of second sub-String together
        reverse(Math.floor(shift / 2), shift + Math.floor(lenFirst / 2) - 1);
  
        // Increase the length of first subarray
        shift += lenFirst;
    }
}
 
// Driver code
let st = "a1b2c3d4e5f6g7";
    str = st.split("");
      
    moveNumberToSecondHalf();
      
    document.write(str.join(""));
 
// This code is contributed by rag2127
</script>
Producción

abcdefg1234567

Complejidad temporal: O(n 2 )
Espacio auxiliar: O(1)

Haga clic aquí para ver varios casos de prueba.
Notas: 

  1. Si el tamaño de la array ya tiene la forma 3^k + 1, podemos aplicar directamente el algoritmo de iteración del líder del ciclo. No hay necesidad de unirse.
  2. El algoritmo de iteración del líder del ciclo solo es aplicable a arrays de tamaño de la forma 3^k + 1.

¿Cómo es la complejidad del tiempo O(n)?  
Cada artículo en un ciclo se desplaza como máximo una vez. Por lo tanto, la complejidad temporal del algoritmo del líder del ciclo es O(n). La complejidad temporal de la operación inversa es O(n). Pronto actualizaremos la prueba matemática de la complejidad temporal del algoritmo.

Ejercicio: 
Dada la string en la forma «abcdefg1234567», conviértala a «a1b2c3d4e5f6g7» en el lugar y en complejidad de tiempo O(n).

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *