Número lexicográfico más pequeño después de un máximo de K intercambios consecutivos

Dado un número en forma de string str y un entero K , la tarea es encontrar el entero más pequeño que se puede formar después de realizar como máximo K intercambios consecutivos.

Los intercambios consecutivos significan que en un intercambio el carácter en el índice i puede intercambiarse con el carácter en el índice i – 1 o i + 1

Ejemplos:

Entrada: str = “76921”, K = 3
Salida: 27691
Explicación:
27691 es el número lexicográfico más pequeño posible.

Entrada: str = “9438957234785635408”, K = 23
Salida: 0345989723478563548
Explicación:
0345989723478563548 es el número lexicográfico más pequeño posible.

 

Enfoque ingenuo: la idea más simple es generar todas las permutaciones posibles de la string dada y verificar si la string lexicográficamente más pequeña satisface las condiciones para un máximo de K intercambios. Imprime esa string.

Complejidad de tiempo: O(N!), donde N es la longitud de la string dada.
Espacio Auxiliar: O(1)

Mejor enfoque: un mejor enfoque es usar Greedy Approach . A continuación se muestran los pasos:

  1. Elimina el cero inicial si existe en el número dado.
  2. Elija el elemento más pequeño de la string str [Considere str[k] cuando K es más pequeño, de lo contrario N ].
  3. Coloque el elemento más pequeño en la posición 0 después de desplazar todos estos elementos 1 posición a la derecha.
  4. Reste el número de intercambios en los pasos anteriores de K .
  5. Si aún nos queda K > 0 , aplicamos el mismo procedimiento desde la siguiente posición inicial, es decir, str[2, …N], y luego lo colocamos en la primera posición.
  6. Así que seguimos aplicando el mismo proceso hasta que K se convierte en 0 .

Complejidad de tiempo: O(N 2 ), donde N es la longitud de la string dada.
Espacio Auxiliar: O(1)

Enfoque eficiente: la idea es utilizar el árbol de segmentos y Hashing . A continuación se muestran los pasos:

  1. Elimina el cero inicial si existe en el número dado.
  2. Almacene la posición original de los dígitos en un mapa y encuentre qué dígito se ajusta mejor a cada índice cuyo desplazamiento será menor que igual a K .
  3. Use un mapa para encontrar la posición original del dígito.
  4. Encuentre el número de dígitos que están a la derecha de la posición actual y que están desplazados, para esto, marque la posición de los cuales están desplazados en un árbol de segmento de [0 … N-1] .
  5. Cada Node del árbol de segmentos contiene el número de posiciones que se desplazaron. Ahora la tarea es encontrar cuántas posiciones se cambiaron en el rango [índice_actual, N-1] porque solo eso afectará la posición original.
  6. La nueva posición a cambiar será (original_position + number_of_right – element_shifted – i), es decir, la posición original del elemento se agrega al árbol de segmentos que se acaba de cambiar.

A continuación se muestra el programa para el enfoque anterior:

C++

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to mark the pos as 1 that
// are shifted in string in Segtree node
void segAdd(vector<int>& seg, int start,
            int end, int pos, int curr)
{
 
    // Out of Range
    if (pos < start or pos > end)
        return;
 
    // Check if we reach the position
    if (start == end) {
        seg[curr] = 1;
        return;
    }
 
    // Initialize the mid
    int mid = (start + end) / 2;
 
    // Recursion call
    segAdd(seg, start, mid, pos,
           2 * curr + 1);
 
    segAdd(seg, mid + 1, end, pos,
           2 * curr + 2);
 
    // Every node contains no of
    // marked position that are
    // shifted in a range
    seg[curr] = seg[2 * curr + 1]
                + seg[2 * curr + 2];
 
    return;
}
 
// Function to find the number of
// elements which got shifted
int segFind(
    vector<int>& seg, int pos_start,
    int pos_end, int start, int end,
    int curr)
{
    // Return 0 is the end position is
    // less than start or the start
    // position is greater than end
    if (pos_end < start
        or pos_start > end)
        return 0;
 
    if (pos_start <= start
        and pos_end >= end)
        return seg[curr];
 
    // Initialize the mid
    int mid = (start + end) / 2;
 
    // Recursion call
    int left = segFind(
        seg, pos_start, pos_end,
        start, mid, 2 * curr + 1);
 
    int right = segFind(
        seg, pos_start, pos_end,
        mid + 1, end, 2 * curr + 2);
 
    // Return the result
    return left + right;
}
 
// Function to remove leading zeros
// from the given string str
string removeLeadingZeros(string str)
{
 
    int i = 0;
 
    // To store the resultant string
    string ans = "";
 
    for (; i < str[i]; i++) {
 
        // If Initial character is 0,
        // then remove it
        if (str[i] == '0') {
            i++;
        }
 
        // Else break
        else {
            break;
        }
    }
 
    ans = str.substr(i - 1,
                     str.length());
 
    // Return the updated string
    return ans;
}
 
// Function to find the lexicographically
// smallest integer
string findMinimumInteger(
    string arr, int k)
{
 
    // To remove leading zeros
    arr = removeLeadingZeros(arr);
 
    int n = arr.size();
 
    // Segment tree vector
    vector<int> seg(
        (2 * (int)pow(
                 2,
                 (int)(ceil(log2(n))))
         - 1),
        0);
 
    // Hash to find the original
    // position of the digit
    unordered_map<int, list<int> > m;
 
    for (int i = 0; i < n; i++) {
        m[arr[i] - '0'].push_back(i);
    }
 
    // Resultant string variable
    string res = "";
 
    for (int i = 0; i < n; i++) {
 
        // Place a digit from
        // 0-9 which fit best
        for (int digit = 0;
             digit <= 9; digit++) {
 
            if (m[digit].size() != 0) {
                int original_pos
                    = m[digit].front();
 
                // Find the number of
                // right elements that
                // are shifted from
                // current element
                int shift
                    = segFind(
                        seg, original_pos,
                        n - 1, 0, n - 1, 0);
 
                // Mark the new position
                int new_pos = original_pos
                              + shift
                              - i;
 
                if (new_pos <= k) {
                    k -= new_pos;
 
                    // Add the original position of
                    // the element which got shifted
                    segAdd(seg, 0, n - 1,
                           original_pos, 0);
 
                    res.push_back('0' + digit);
                    m[digit].pop_front();
                    break;
                }
            }
        }
    }
 
    // Return the result
    return res;
}
 
// Driver Code
int main()
{
    // Given string
    string s = "9438957234785635408";
 
    // Given K swaps
    int k = 23;
 
    // Function Call
    cout << findMinimumInteger(s, k)
         << endl;
}
Producción: 

0345989723478563548

 

Complejidad de tiempo: O(N * log N), donde N es la longitud de la string.
Espacio Auxiliar: O(N)

Publicación traducida automáticamente

Artículo escrito por godaraji47 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 *