- Grabado el 21 de mayo de 2019
17. Combinación de letras del número de teléfono
- Dada una cadena que contiene solo números del 2 al 9, devuelve todas las combinaciones de letras que pueda representar.
- La asignación de números a letras se da de la siguiente manera (igual que los botones del teléfono). Tenga en cuenta que 1 no corresponde a ninguna letra.
- Ejemplo:
Entrada: "23"
Salida: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Explicación: A pesar de lo anterior Las respuestas están organizadas en orden lexicográfico, pero puede elegir el orden en el que se emiten.
② Convierta el problema combinatorio (que requiere varios ciclos) en una multiplicación: la velocidad es inesperadamente rápida.
- Según el significado del título, si el número es
“23”
, la última combinación de letras es amable3 x 3 = 9
; si el número es“234”
, la última combinación de letras es amable9 x 3 = 27
. Este es un problema de combinación. Debe haber algunos números y se necesitan varias capas de bucles para obtener todas las combinaciones de letras. - No hay forma de escribir un bucle multicapa sin conocer el número de números. Así que cámbielo para multiplicar. Cuando la longitud de list1 sea 0, regrese a list2 directamente; de lo contrario, use un bucle de 2 capas para combinar las letras en list1 y list2.
- De esta manera, las
“234”
combinaciones de letras correspondientes se pueden combinar en3 x 3 x 3 = 27
multiplicaciones. - el código se muestra a continuación:
public List<String> letterCombinations(String digits) {
List<String> result = new ArrayList<>();
if (digits == null || digits.length() == 0) {
return result;
}
for (int i = 0; i < digits.length(); i++) {
result = mul(result, getList(digits.charAt(i) - '0'));
}
return result;
}
public List<String> getList(int num) {
String digitLetter[] = {
"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
List<String> res = new ArrayList<>();
for (int i = 0; i < digitLetter[num].length(); i++) {
res.add(digitLetter[num].charAt(i) + "");
}
return res;
}
public List<String> mul(List<String> list1, List<String> list2) {
if (list1.size() == 0 && list2.size() != 0) {
return list2;
}
List<String> res = new ArrayList<>();
for (int i = 0; i < list1.size(); i++) {
for (int j = 0; j < list2.size(); j++) {
res.add(list1.get(i) + list2.get(j));
}
}
return res;
}
③ Usar recursividad
- Se puede ver en el gráfico dinámico que todas las combinaciones de letras posibles se pueden obtener usando la recursividad.
Backtracking es un algoritmo para encontrar todas las soluciones mediante la exploración de todos los candidatos potenciales. Si la solución candidata resulta no ser una solución (o al menos no la última), el algoritmo de retroceso lo descarta haciendo algunos cambios en el paso anterior, es decir, retrocede y luego vuelve a intentarlo.
- Cuando la longitud de los dígitos es 0, indica que se ha encontrado la última combinación y se agrega directamente al resultado.
String digitLetter[] = {
"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
List<String> result = new ArrayList<>();
public List<String> letterCombinations(String digits) {
if (digits.length() == 0 || digits == null) {
return result;
}
helper("", digits);
return result;
}
public void helper(String com, String digits) {
if (digits.length() == 0) {
result.add(com);
} else {
int index = digits.charAt(0) - '0';
for (int i = 0; i < digitLetter[index].length(); i++) {
helper(com + digitLetter[index].charAt(i), digits.substring(1));
}
}
}
④ iteración de la cola
- Utilice inteligentemente la
LinkedList
lista doblemente enlazada, elimine las combinaciones que cumplan las condiciones de la cabeza y agregue nuevas combinaciones de la cola. - Elimina del encabezado la combinación que cumple las condiciones. La longitud de la combinación debe ser la misma que el índice del número actual. Cuando el índice es 0, la longitud de la combinación es 0, por lo que debe agregarse por adelantado
""
; cuando el índice es 1, elimine (eg: 'a', 'b', 'c'
) todas las combinaciones de longitud 1 en la cabecera y combínelas con las letras del número actual para formar una nueva combinación, y luego Agrega la cola.
String digitLetter[] = {
"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public List<String> letterCombinations(String digits) {
LinkedList<String> result = new LinkedList<>();
if (digits.length() == 0 || digits == null) {
return result;
}
result.add("");
for (int i = 0; i < digits.length(); i++) {
int index = digits.charAt(i) - '0';
while (result.peek().length() == i) {
String com = result.remove();
for (int j = 0; j < digitLetter[index].length(); j++) {
result.add(com + digitLetter[index].charAt(j));
}
}
}
return result;
}
19. Elimina el nodo N de la parte inferior de la lista vinculada.
① Descripción del título
- Dada una lista vinculada, elimine el n-ésimo nodo de la parte inferior de la lista vinculada y devuelva el nodo principal de la lista vinculada.
- Ejemplo:
Dada una lista vinculada: 1-> 2-> 3-> 4-> 5, y n = 2.
Cuando se elimina el penúltimo nodo, la lista vinculada se convierte en 1-> 2-> 3-> 5.
Explicación: Las n garantías dadas son válidas.
- Avanzado:
¿Puedes intentar usar un escaneo para lograrlo?
② Dos recorridos
- Un recorrido se usa para obtener la longitud de la lista enlazada, y un recorrido se usa para encontrar la anterior del nodo eliminado y luego actualizar el punto anterior.
- Después del primer recorrido, si len es el mismo que el índice que se va a eliminar, significa que se elimina el primer nodo, así que siga recto
return head.next;
.
public ListNode removeNthFromEnd(ListNode head, int n) {
int len = 0;
ListNode p = head;
while (p != null) {
len++;
p = p.next;
}
if (len == n) {
return head.next;
}
ListNode prev;
p = head;
int cur = 0;
while (p != null) {
cur++;
if (cur == len - n) {
prev = p;
prev.next = prev.next.next;
break;
}
p = p.next;
}
return head;
}
③ Travesía única
- La idea principal: en contraste con la lista, establecemos dos punteros (
first
ysecond
), dejamos que elfirst
puntero atraviese eln + 1
paso y luego dejamos que Talia mientras atraviesa. En este caso, cuandofirst
llega el punteronull节点
, elsecond
puntero está a una distancia de n del primer puntero, por lo quesecond
la posición del puntero es exactamente esa倒数第 n 个结点的prev
. - Características:
① Necesita agregar undummy
nodo como una nueva cabeza;
② Elfirst
puntero se ejecuta primero, no n pasos, sinon + 1
pasos;
③ Cuando se ejecuta al mismo tiempo,first
deténgase cuando el puntero apunte a nulo.
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy, second = dummy;
for (int i = 1; i <= n + 1; i++) {
first = first.next;
}
while (first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
}