Preguntas de la entrevista de cadenas de Java

Sin duda, la clase String es la clase más utilizada en Java, representando una secuencia de caracteres, tratados como un objeto. Dado el papel por excelencia de...

Introducción

Sin duda, la clase String es la clase más utilizada en Java, representando una secuencia de caracteres, tratados como un objeto. Dado el papel por excelencia de Strings en prácticamente todas las aplicaciones de Java, los reclutadores prestan mucha atención a las preguntas relacionadas con String durante una entrevista de trabajo. Al ir a una entrevista, un desarrollador de Java debe tener un control y un conocimiento completos y profundos de esta clase.

Aún mejor, también debe prepararse para su entrevista estudiando las preguntas de entrevistas anteriores utilizadas por las principales empresas, lo que puede hacer con [Problema de codificación diaria] (http://stackabu.se/daily-coding-problem). Con DCP, las preguntas de práctica se le envían por correo electrónico todos los días. Aunque, si necesita estudiar Java Strings en particular, siga leyendo.

Preguntas de entrevista de cadena Java

Las entrevistas de trabajo a menudo distinguen dos categorías de preguntas: teóricas y de codificación:

Preguntas teóricas

Clases de cadenas

Pregunta

"¿Qué clases de String conoces?

Responder

Esta pregunta puede sonar confusa al principio, pero no te preocupes, en realidad es bastante simple.

Una cadena es una secuencia de caracteres, y la clase String no es la única que hace eso. Hay tres clases en Java que se utilizan para crear objetos String: String, StringBuffer y StringBuilder. En realidad, este es un tema bastante profundo al considerar las diferencias entre las clases y sus ventajas/desventajas.

Si desea leer más sobre esto en detalle, consulte nuestro artículo sobre el tema - Cadena frente a StringBuilder frente a StringBuffer.

Inmutabilidad de cadenas {#inmutabilidad de cadenas}

Pregunta

"¿Es String una clase inmutable, y si es así, por qué?"

Respuesta

Esta es una pregunta muy común en las entrevistas y una respuesta de “Sí” o “No” generalmente no es suficiente. Por lo general, deberá poder explicar más.

String es una clase inmutable. Esto significa que una vez que se crea una instancia de un objeto String, no se puede modificar. Este es ante todo el efecto del modificador final aplicado a la clase String. Llamar a cualquier tipo de método de modificación de contenido en una instancia de String simplemente devolverá una instancia de String nueva y actualizada: el objeto original no cambia.

Esto se puede observar fácilmente en el código fuente de cualquier método String:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

El str original nunca se cambia, porque no se puede cambiar. En última instancia, el método devuelve un nuevo objeto String.

Conjunto de cadenas {#conjunto de cadenas}

Pregunta

"¿Qué es el String Pool?"

Respuesta

Como se mencionó, las cadenas se usan con mucha frecuencia. Aprovechando el hecho de que son inmutables, la JVM guarda todos los literales de cadena en la Memoria Heap. Cada vez que creamos una instancia implícita de un objeto String, su valor literal se compara con los de la Memoria Heap y, si ya existe, la variable de referencia se asigna a la ubicación de memoria ya existente.

Este enfoque puede ahorrar memoria drásticamente ya que no hay valores duplicados. Esta colección de ubicaciones de memoria guardadas se llama String Pool.

Herencia de cadena {#herencia de cadena}

Pregunta

"¿Puedes extender String?"

Respuesta

Dado que la clase String se declara como final, no se puede heredar.

== vs .igual()

Pregunta

"¿Hay alguna diferencia entre el operador == y el método .equals()?"

Respuesta

Aunque pueden parecer iguales, hay una clara diferencia entre estos dos validadores de igualdad:

  • El operador == verifica la igualdad de las variables de referencia y devuelve true si ambas apuntan al mismo objeto en la memoria.
  • El método .equals() es un método que compara dos cadenas en función de su contenido y devuelve verdadero si son iguales.

Usar el operador == para comparar cadenas puede devolver el resultado esperado, debido a que el grupo de cadenas guarda valores en la misma ubicación de memoria, aunque a menudo no lo hará.

Por otro lado, .equals() siempre devolverá el resultado esperado al comparar cadenas.

Índice de caracteres

Pregunta

"¿Cómo encuentras el valor de un carácter en una posición específica?"

Respuesta

La clase String proporciona un método .charAt(int position) que devuelve un solo carácter. El carácter que devolverá el método depende del argumento 'posición' especificado.

Como en una matriz, 0 representa el índice del primer carácter en una cadena y .length() - 1 representa el índice del último carácter.

Concatenación de cadenas

Pregunta

"¿De qué manera se puede realizar la concatenación de cadenas?"

Respuesta

La concatenación es una operación utilizada para fusionar dos cadenas en una nueva. Las cadenas básicas se pueden concatenar simplemente usando el operador + o usando el método .concat(), mientras que StringBuffers y StringBuilders logran la concatenación usando el método .append().

Cuando se usa el operador + con otros tipos de datos, si es posible, se convierten en una cadena.

Otra forma de unir múltiples Strings es usando la clase StringJoiner:

1
2
3
4
5
6
7
// The delimeter is "", the prefix is "[" and the suffix is "+"
StringJoiner joiner = new StringJoiner("", "[", "+");
joiner.add("Orange")
  .add("Apple")
  .add("Pear");
  
System.out.println(joiner.toString());

La salida sería:

1
[OrangeApplePear+

Seguridad de subprocesos de cadena

Pregunta

"¿Las cadenas son seguras para subprocesos?"

Respuesta

En Java, cada objeto inmutable es seguro para subprocesos y, por lo tanto, String también es seguro para subprocesos.

Esto aplica a StringBuffer ya que usa Palabra clave sincronizada de Java, pero no aplica a StringBuilder, que es\ ’t thread-safe ya que es mutable y no usa la palabra clave synchronized.

Cadena frente a StringBuilder frente a StringBuffer

Pregunta

"¿Cuáles son las diferencias entre las clases String, StringBuilder y StringBuffer?

Respuesta

Los objetos de cadena son más fáciles de usar, seguros para subprocesos e inmutables, lo que significa que consumen más memoria y son más lentos que sus hermanos (StringBuffer y StringBuilder) en lo que respecta a la manipulación de cadenas.

Los objetos StringBuffer son mutables, eficientes en memoria y seguros para subprocesos, pero siguen siendo lentos en comparación con StringBuilder.

Los objetos StringBuilder también son mutables, eficientes en memoria y extremadamente rápidos, pero no son seguros para subprocesos.

Si quieres leer más sobre Cadenas, StringBuffers y StringBuilders, tenemos un artículo completo que profundiza en tema.

Preguntas de codificación {#preguntas de codificación}

Invertir una cadena

Para revertir una cadena, tendríamos que escribir una función personalizada, ¿verdad? Bueno, hay una solución para este caso: podemos usar StringBuilder o StringBuffer como un envoltorio alrededor de nuestro objeto String.

De esa forma podemos acceder a la función .reverse() y usarla para invertir nuestra Cadena sin crear una nueva función personalizada para exactamente la misma tarea:

1
2
3
4
5
6
7
8
String str = "I'm a string waiting to be reversed";
System.out.println(str);

StringBuilder stringBuilder = new StringBuilder(str);
stringBuilder.reverse();
System.out.println("Reversing the string. . .\n");

System.out.println(stringBuilder.toString());

Producción:

1
2
3
4
I'm a string waiting to be reversed
Reversing the string. . .

desrever eb ot gnitiaw gnirts a m'I

Sin embargo, si el reclutador no aprecia que utilices esta solución alternativa, hay muchas formas de revertir una cadena carácter por carácter. Vamos a enumerar un par:

**1. Inversión por matriz de caracteres: **

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public String reverse(String str) {
    char[] characters = str.toCharArray();
    int start = 0;
    int finish = characters.length-1;
    char temp;
    
    while(finish > start) {
        temp = characters[start];
        characters[start] = characters[finish];
        characters[finish] = temp;
        finish--;
        start++;
    }
    return new String(in);
}

Este enfoque es muy eficiente, ya que simplemente reorganiza los caracteres y devuelve un nuevo objeto String con la matriz pasada al constructor.

2. Inversión por apilamiento de caracteres:

1
2
3
4
5
6
7
public String reverse(String str) {
    String result = "";
    for(int i = str.length() - 1; i >= 0; i--) {
        result = result + string.charAt(i);
    }
    System.out.println(result); 
}

Aunque, este enfoque no es tan eficiente debido a la creación de un nuevo objeto String a través de la concatenación de cada carácter.

Comprobar si la cadena contiene solo dígitos

El enfoque más fácil para verificar si la cadena contiene solo dígitos es usar el método .matches() y proporcionar un argumento de cadena - "[0-9]+". El argumento esperado debe ser una expresión regular (Expresión regular) con la que debe coincidir la cadena; en nuestro caso, la expresión regular representa los caracteres numéricos del 0 al 9.

1
2
3
4
5
6
7
String str = "09";
        
if (str.matches("[0-9]+")) {
    System.out.println("String contains only numbers.");
} else {
    System.out.println("String doesn't contain only numbers!");
}

Producción:

1
String contains only numbers.

Cómo convertir una cadena a entero

La clase Integer proporciona tres métodos que nos permiten convertir cadenas en enteros:

  • parseInt()
  • valorDe()
  • decodificar()

Estos son bastante sencillos y devuelven números enteros con una cadena pasada:

1
2
3
4
5
6
7
8
String str = "1234";
int strNumber = Integer.parseInt(str);
int strNumber2 = Integer.valueOf(str);
int strNumber3 = Integer.decode(str);

System.out.println(4321 + strNumber);
System.out.println(4321 + strNumber);
System.out.println(4321 + strNumber);

Producción:

1
2
3
5555
5555
5555

Si desea leer todos los casos de uso de estos métodos, así como sus diferencias, tenemos un excelente artículo sobre convertir cadenas a enteros que cubre el tema con más detalle.

Eliminación de caracteres duplicados en una cadena

Para eliminar los caracteres duplicados en una cadena, podemos usar HashSets, Streams e incluso LinkedLists. Pero para este ejemplo en particular, vamos a usar solo objetos String y encontrar la solución implementando la lógica adecuada.

En primer lugar, necesitamos dos cadenas: una contendrá la cadena de entrada y la otra contendrá el resultado "filtrado". Después de eso, creamos un ciclo que debe iterar a través de nuestra cadena de entrada, 1 carácter a la vez.

Utilizaremos un indicador booleano, inicialmente establecido en falso. El ciclo interno itera a través de la Cadena resultado, comparando los caracteres de la primera Cadena con la segunda:

  • Si el carácter no está presente en la segunda Cadena, lo agregamos.
  • Si el carácter está presente en la segunda Cadena, marcamos el indicador booleano como “verdadero”, lo que excluye el carácter de la concatenación.

Aquí está la implementación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
String str = "wikihtp";
String str2 = "";
for (int i = 0; i < str.length(); i++) {
    boolean found = false;
    for (int j = 0; j < str2.length(); j++) {
        if (str.charAt(i) == str2.charAt(j)) {
            found = true;
            break;
        }
    }
    if (found == false) {
        str2 = str2.concat(String.valueOf(str.charAt(i)));
    }
}
System.out.println(str2);

Producción:

1
stackbue

Encontrar el carácter máximo que aparece en una cadena {#encontrar el carácter máximo que aparece en una cadena}

El mejor método para encontrar el carácter máximo que aparece en una cadena es usar HashMaps. Para encontrar el carácter correcto, así como el número de ocurrencias, nuestro HashMap debe contener una clave char y un valor int.

La lógica aquí es simple: verifique cada carácter en una cadena y si un carácter ya existe en un ‘HashMap’, incremente su valor, de lo contrario, guarde el carácter en un ‘HashMap’ y asígnele el valor de 1. Para cada carácter estamos comprobando si su valor es mayor que la variable charCount que cuenta la ocurrencia máxima y si lo es, incrementamos charCount.

Al final, iteramos a través de HashMap y buscamos una clave que tenga charCount el número de ocurrencias y cuando la encontramos, simplemente la imprimimos. Si hay varios caracteres con el mismo valor charCount, todos se imprimen en la consola:

 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
26
27
28
29
30
31
32
33
34
35
36
public static void findMaxOccurrence(String input) {
    int charCount = 0;
    HashMap<Character, Integer> map = new HashMap<>();
    char[] inputChar = input.toCharArray();
    
    for (int i = 0; i < inputChar.length; i++) {
        char c = inputChar[i];
        
        if (map.containsKey(c)) {
            int count = map.get(c);
            count++;
            
            if (charCount < count) {
                charCount++;
            }
            
            map.put(c, count);
        } else {
            map.put(c, 1);
        }
    }

    Set set = map.keySet();
    Iterator<Character> iterator = set.iterator();
    while (iterator.hasNext()) {
        char key = iterator.next();
        
        if (map.get(key) == charCount) {
            System.out.println("Character '" + key + "' has the max occurrence: " + charCount + " times!");
        }
    }
}
    
public static void main(String[] args) {
    Main.findMaxOccurrence("This is the best example");
}

Producción:

1
2
Character ' ' has the max occurrence: 4 times!
Character 'e' has the max occurrence: 4 times!

Encuentra el primer carácter que no se repite en una cadena {#busca el primer carácter que no se repite en una cadena}

Entonces, necesitamos encontrar el primer carácter que no se repite en una Cadena, eso significa que debemos recorrer todos los caracteres de esa Cadena, compararlos y tan pronto como encontremos el primer carácter que no se repite, lo imprimimos y el trabajo está hecho.

Esto se hace fácilmente usando una bandera booleana y dos bucles. Para cada carácter, iteramos a través del resto de la cadena de entrada. Si el carácter del primer ciclo coincide con cualquiera de los caracteres del segundo ciclo, la bandera se establece en “verdadero”.

Si la bandera es falsa, lo que significa que no encontramos al menos dos ocurrencias del mismo carácter, separamos e imprimimos el carácter:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
String str = "wikihtp";
for (int i = 0; i < str.length(); i++) {
    boolean found = false;
    for (int j = 0; j < str.length(); j++) {
        if (i != j) {
            if (str.charAt(i) == str.charAt(j)) {
                found = true;
            }
        }
    }
    if (!found) {
        System.out.println("The first non-repeating character is: '" + str.charAt(i) + "'");
        break;
    } else if (found && i == str.length() - 1) {
        System.out.println("There is no non-repeating character in this string!");
    }
}

Producción:

1
The first non-repeating character is: 't'

Verificar si dos cadenas son anagramas entre sí {#verificar si dos cadenas son anagramas entre sí}

Para esta pregunta, crearemos un método personalizado que verifique si dos cadenas dadas son anagramas y devuelva un valor booleano apropiado.

En primer lugar, modificamos nuestras dos cadenas eliminando todos los espacios en blanco que puedan tener. Después de recortarlos, comparamos su longitud; si no tienen la misma longitud, no hay posibilidad de que puedan ser anagramas entre sí, por lo que, si ese es el caso, devolvemos falso.

De lo contrario, transformamos nuestras cadenas en matrices de caracteres y convertimos su contenido en letras minúsculas. Finalmente, Arrays.sort() se llama para ambos Strings y ordena los caracteres por orden alfabético y devolvemos el resultado de una función Arrays.equals() que compara dos matrices de caracteres y devuelve true si tienen los mismos personajes:

 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
26
27
public static boolean checkAnagram(String str, String str2) {
    str = str.replaceAll("\\s", "");
    str2 = str2.replaceAll("\\s", "");

    if (str.length() != str2.length()) {
        return false;
    } else {
        char[] strCharArray = str.toLowerCase().toCharArray();
        char[] strCharArray2 = str2.toLowerCase().toCharArray();

        Arrays.sort(strCharArray);
        Arrays.sort(strCharArray);

        return (Arrays.equals(strCharArray, strCharArray));
    }
}
    
public static void main(String[] args) {
    String str = "wikihtp";
    String str2 = "Backseat Us";

    if (checkAnagram(str, str2)) {
        System.out.println(str + " and " + str2 + " are Anagrams!");
    } else {
        System.out.println(str + " and " + str2 + " are not Anagrams!");
    }
}

Producción:

1
wikihtp and Backseat Us are Anagrams!

Contar el número de palabras en una cadena {#contar el número de palabras en una cadena}

Para lograr esto, debemos dividir nuestra Cadena en partes más pequeñas (palabras) y usar un carácter de espacio como delimitador:

1
2
3
4
String str = "Java is an awesome programming language!";
str = str.trim().replaceAll("\\s{2,}", " ");
String splitStr[] = str.split(" ");
System.out.println("The provided string '" + str + "' contains " + splitStr.length + " words!");

Producción:

1
The provided string 'Java is an awesome programming language!' contains 6 words!

Conclusión

En este artículo, hemos cubierto las preguntas comunes de la entrevista relacionadas con las cadenas.

Si estás interesado en leer más sobre Preguntas de la entrevista de programación en general, hemos compilado una larga lista de estas preguntas, incluyendo su explicaciones, implementaciones, representaciones visuales y aplicaciones.

También te recomendamos encarecidamente que consultes Problema de codificación diaria si te tomas en serio mejorar tu capacidad para resolver las preguntas de programación que realmente plantean las principales empresas tecnológicas.