Método de alta resolución Go-Python-Java-C-LeetCode: colección de la séptima semana

Prefacio

La parte del lenguaje Go de esta solución de problema se basa en LeetCode-Go.
Las otras partes se basan en mi aprendizaje práctico.
Solución de problema personal Enlace de GitHub: LeetCode-Go-Python-Java-C

Método de alta descomposición Go-Python-Java-C-LeetCode: recopilación de la primera semana
Método de alta descomposición Go-Python-Java-C-LeetCode: recopilación de la segunda semana
Método de alta descomposición Go-Python-Java-C-LeetCode: colección de la tercera semana
Go- Método de alta descomposición Python-Java-C-LeetCode: colección de la cuarta semana
Método de alta descomposición Go-Python-Java-C-LeetCode: colección de la quinta semana
Método de alta descomposición Go-Python-Java-C-LeetCode:
parte de la colección Zhou de la sexta semana Gran parte del contenido de este artículo proviene de colecciones en línea y de práctica personal. Si alguna información contiene errores, los lectores pueden criticarla y corregirla. Este artículo es sólo para aprendizaje y comunicación, no para fines comerciales. Bienvenido a suscribirse a la columna, una pregunta cada día y mejorar la columna LeetCode
con los bloggers.

43. Multiplicar cadenas

tema

Dados dos números enteros no negativos num1y num2representados como cadenas, devuelve el producto de num1y num2, también
representado como una cadena.

**Nota:** No debe utilizar ninguna biblioteca BigInteger incorporada ni convertir las entradas a números enteros directamente.

Ejemplo 1:

Input: num1 = "2", num2 = "3"
Output: "6"

Ejemplo 2:

Input: num1 = "123", num2 = "456"
Output: "56088"

Restricciones:

  • 1 <= num1.length, num2.length <= 200
  • num1y num2consta únicamente de dígitos.
  • Ambos num1y num2no contienen ningún cero a la izquierda, excepto el número 0mismo.

La idea general del tema.

Dados dos enteros no negativos num1 y num2 representados como cadenas, devuelve el producto de num1 y num2, también representados como cadenas.

Ideas para resolver problemas

  • Simular la multiplicación con matrices. Cree una len(num1) + len(num2)
    matriz de longitud para almacenar el producto. Para cualquiera 0 ≤ i < len(num1), el resultado de está en , si , entonces se suma la parte de 0 ≤ j < len(num2)acarreo . Finalmente, convierte el array en una cadena, descartando el bit más alto si es 0. A continuación se presentan las ideas de resolución de problemas para cada versión:num1[i] * num2[j]tmp[i+j+1]
    tmp[i+j+1]≥10tmp[i+j]tmp

Ir a la versión de ideas para resolver problemas

  1. Primero, verifique si la entrada num1y num2es "0", si uno de ellos es "0", luego devuelva "0", porque cualquier número multiplicado por 0 es igual a 0.

  2. Crea un segmento entero tmpde longitud len(num1) + len(num2)para almacenar los resultados intermedios de la multiplicación.

  3. Utilice un bucle anidado para iterar sobre cada carácter de num1y num2, multiplique los números en las posiciones correspondientes y acumule los resultados en las tmpposiciones apropiadas en.

  4. Manejar el acarreo: recorra de derecha a izquierda tmp, agregue el acarreo de cada bit al bit anterior y tome el módulo de bit actual 10 para mantenerlo en el rango de 0 a 9.

  5. Si tmpel bit más alto es 0, elimine el 0 del bit más alto.

  6. Convierta tmplos números del segmento en caracteres y cree la cadena resultante.

  7. Devuelve la cadena de resultado.

Ideas para resolver problemas de la versión Python

  1. Primero, verifique si la entrada num1y num2es "0", si uno de ellos es "0", luego devuelva "0", porque cualquier número multiplicado por 0 es igual a 0.

  2. int()Utilice la función incorporada para convertir num1y num2a números enteros, luego multiplíquelos para obtener un resultado entero.

  3. Convierta el resultado entero en una cadena y devuélvalo.

Ideas para resolver problemas de la versión Java

  1. Primero, verifique si la entrada num1y num2es "0", si uno de ellos es "0", luego devuelva "0", porque cualquier número multiplicado por 0 es igual a 0.

  2. Convierte num1y num2a matrices de caracteres b1y b2.

  3. Cree una matriz de números enteros tmpde longitud num1.length() + num2.length()para almacenar los resultados intermedios de la multiplicación.

  4. Utilice un bucle anidado para iterar sobre cada carácter de b1y b2, multiplique los números en las posiciones correspondientes y acumule los resultados en las tmpposiciones apropiadas en.

  5. Manejar el acarreo: recorra de derecha a izquierda tmp, agregue el acarreo de cada bit al bit anterior y tome el módulo de bit actual 10 para mantenerlo en el rango de 0 a 9.

  6. Si tmpel bit más alto es 0, elimine el 0 del bit más alto.

  7. Construye la cadena resultante, convirtiendo tmplos números de la matriz en caracteres.

  8. Devuelve la cadena de resultado.

Ideas para resolver problemas de la versión C ++

  1. Primero, verifique si la entrada num1y num2es "0", si uno de ellos es "0", luego devuelva "0", porque cualquier número multiplicado por 0 es igual a 0.

  2. Convierte num1y num2a matrices de caracteres b1y b2.

  3. Cree una matriz de números enteros tmpde longitud num1.length() + num2.length()para almacenar los resultados intermedios de la multiplicación.

  4. Utilice un bucle anidado para iterar sobre cada carácter de b1y b2, multiplique los números en las posiciones correspondientes y acumule los resultados en las tmpposiciones apropiadas en.

  5. Manejar el acarreo: recorra de derecha a izquierda tmp, agregue el acarreo de cada bit al bit anterior y tome el módulo de bit actual 10 para mantenerlo en el rango de 0 a 9.

  6. Si tmpel bit más alto es 0, elimine el 0 del bit más alto.

  7. Construye la cadena resultante, convirtiendo tmplos números de la matriz en caracteres.

  8. Devuelve la cadena de resultado.

En términos generales, las ideas de resolución de problemas de estas versiones son similares: todas simulan el proceso de multiplicación manual, almacenan el producto de cada bit en la matriz intermedia y luego manejan el acarreo y construyen la cadena del resultado final. Los diferentes lenguajes de programación tienen diferentes sintaxis y estructuras de datos, pero la idea básica es la misma.

código

Ir

func multiply(num1 string, num2 string) string {
    if num1 == "0" || num2 == "0" {
        return "0"
    }

    // 将输入的两个字符串转换为字节数组
    b1, b2, tmp := []byte(num1), []byte(num2), make([]int, len(num1)+len(num2))

    // 使用嵌套循环遍历两个输入字符串的每一位数字进行相乘,结果存储在 tmp 数组中
    for i := 0; i < len(b1); i++ {
        for j := 0; j < len(b2); j++ {
            tmp[i+j+1] += int(b1[i]-'0') * int(b2[j]-'0')
        }
    }

    // 处理进位,将 tmp 数组中的每一位数字都保留在 0 到 9 的范围内
    for i := len(tmp) - 1; i > 0; i-- {
        tmp[i-1] += tmp[i] / 10
        tmp[i] = tmp[i] % 10
    }

    // 如果最高位是0,则去除最高位的0
    if tmp[0] == 0 {
        tmp = tmp[1:]
    }

    // 将结果从整数数组转换回字符串
    res := make([]byte, len(tmp))
    for i := 0; i < len(tmp); i++ {
        res[i] = '0' + byte(tmp[i])
    }
    return string(res)
}

Pitón

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        return str(int(num1) * int(num2))

Java

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }

        char[] b1 = num1.toCharArray();
        char[] b2 = num2.toCharArray();
        int[] tmp = new int[num1.length() + num2.length()];

        for (int i = 0; i < b1.length; i++) {
            for (int j = 0; j < b2.length; j++) {
                tmp[i + j + 1] += (b1[i] - '0') * (b2[j] - '0');
            }
        }

        for (int i = tmp.length - 1; i > 0; i--) {
            tmp[i - 1] += tmp[i] / 10;
            tmp[i] = tmp[i] % 10;
        }

        if (tmp[0] == 0) {
            tmp = Arrays.copyOfRange(tmp, 1, tmp.length);
        }

        StringBuilder result = new StringBuilder();
        for (int num : tmp) {
            result.append(num);
        }

        return result.toString();
    }
}

cpp

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1 == "0" || num2 == "0") {
            return "0";
        }

        vector<char> b1(num1.begin(), num1.end());
        vector<char> b2(num2.begin(), num2.end());
        vector<int> tmp(num1.length() + num2.length(), 0);

        for (int i = 0; i < b1.size(); i++) {
            for (int j = 0; j < b2.size(); j++) {
                tmp[i + j + 1] += (b1[i] - '0') * (b2[j] - '0');
            }
        }

        for (int i = tmp.size() - 1; i > 0; i--) {
            tmp[i - 1] += tmp[i] / 10;
            tmp[i] = tmp[i] % 10;
        }

        if (tmp[0] == 0) {
            tmp.erase(tmp.begin());
        }

        string result;
        for (int num : tmp) {
            result += to_string(num);
        }

        return result;
    }
};

Cuando se utilizan diferentes lenguajes de programación para implementar el mismo algoritmo, es necesario dominar los conocimientos básicos y la sintaxis asociados con ese lenguaje. A continuación se muestra un desglose de los requisitos de conocimientos básicos para cada edición:

Ir versión

  1. Tipos de datos y variables : obtenga información sobre los tipos de datos básicos en Go, como números enteros, cadenas y matrices. Aprenda a declarar y utilizar variables.

  2. Sector : los sectores en Go son matrices dinámicas y es necesario comprender cómo crear, manipular y usar sectores para manejar matrices de caracteres.

  3. Bucles : obtenga información sobre las declaraciones de bucle en Go forpara realizar bucles anidados en caracteres de dos cadenas.

  4. Declaraciones condicionales : obtenga información sobre las declaraciones condicionales en Go ifpara manejar casos especiales, como cuando el multiplicador es "0".

  5. Operaciones de matrices y sectores : comprenda cómo acceder a los elementos de matrices y sectores, y cómo iterar sobre matrices y sectores.

Versión de Python

  1. Tipos de datos y variables : aprenda sobre los tipos de datos básicos en Python, como números enteros, cadenas y listas. Aprenda a declarar y utilizar variables.

  2. Manipulación de cadenas : existen poderosas capacidades de manipulación de cadenas en Python que requieren comprender cómo acceder a los caracteres de una cadena, dividir una cadena y convertir una cadena en un número entero.

  3. Buclesfor : aprenda sobre bucles y declaraciones de bucle en Python whilepara realizar bucles anidados en caracteres de dos cadenas.

  4. Declaraciones condicionales : obtenga información sobre las declaraciones condicionales en Python ifpara manejar casos especiales, como cuando el multiplicador es "0".

  5. Lista : aprenda a crear, manipular y utilizar estructuras de datos de lista en Python para almacenar resultados intermedios.

versión java

  1. Clases y objetos : Java es un lenguaje de programación orientado a objetos y es necesario saber cómo crear clases y objetos para organizar el código.

  2. Tipos de datos y variables : comprenda los tipos de datos básicos en Java, como números enteros, cadenas y matrices de caracteres. Aprenda a declarar y utilizar variables.

  3. Operaciones de matriz de caracteres : aprende a crear matrices de caracteres en las que almacenar los caracteres de una cadena y realizar operaciones entre caracteres.

  4. Buclesfor : aprenda sobre bucles y declaraciones de bucle en Java whilepara realizar bucles anidados en caracteres de dos matrices de caracteres.

  5. Declaraciones condicionales : obtenga información sobre las declaraciones condicionales en Java ifpara manejar casos especiales, como cuando el multiplicador es '0'.

  6. Operaciones de cadenas : Java proporciona muchos métodos de manipulación de cadenas, que requieren conocimiento de cómo acceder a los caracteres de una cadena, convertir una cadena en un número entero y cómo construir la StringBuildercadena resultante usando clases.

versión C++

  1. Tipos de datos y variables : comprenda los tipos de datos básicos en C++, como números enteros, cadenas y matrices. Aprenda a declarar y utilizar variables.

  2. Operaciones de matriz de caracteres : aprende a crear matrices de caracteres en las que almacenar los caracteres de una cadena y realizar operaciones entre caracteres.

  3. Buclesfor : obtenga información sobre bucles y declaraciones de bucle en C++ whilepara realizar bucles anidados en caracteres de dos matrices de caracteres.

  4. Declaraciones condicionales : obtenga información sobre las declaraciones condicionales en C++ ifpara manejar casos especiales, como cuando el multiplicador es "0".

  5. Operaciones de cadenas : C++ proporciona muchas funciones de manipulación de cadenas, lo que requiere conocimiento sobre cómo acceder a los caracteres de una cadena, convertir una cadena en un número entero y cómo construir la stringstreamcadena resultante usando .

Cualquiera que sea la versión que elija, deberá estar familiarizado con los tipos de datos básicos, declaraciones de variables, bucles, declaraciones condicionales y operaciones relacionadas con cadenas y matrices de caracteres. Además, comprender cómo manejar casos especiales (por ejemplo, un multiplicador de "0") y cómo convertir el resultado de otros tipos de datos a una cadena también son puntos clave para resolver este problema.

44. Coincidencia de comodines

Dadas una cadena de entrada y un patrón (p), implemente la coincidencia de patrones comodín con soporte para '?' y donde:

'?' Coincide con cualquier carácter individual.
'*' Coincide con cualquier secuencia de caracteres (incluida la secuencia vacía).
La coincidencia debe cubrir toda la cadena de entrada (no parcial).

Ejemplo 1:

Entrada: s = “aa”, p = “a”
Salida: false
Explicación: “a” no coincide con la cadena completa “aa”.
Ejemplo 2:

Entrada: s = “aa”, p = " "
Salida: verdadero
Explicación: '
' coincide con cualquier secuencia.
Ejemplo 3:

Entrada: s = “cb”, p = “?a”
Salida: false
Explicación: '?' coincide con 'c', pero la segunda letra es 'a', que no coincide con 'b'.

Restricciones:

0 <= s.length, p.length <= 2000
s contiene solo letras minúsculas en inglés.
p contiene sólo letras minúsculas en inglés, '?' o '*'.

La idea general del tema.

Dadas una(s) cadena(s) de entrada y un patrón de caracteres§, implemente una coincidencia con comodines que admita las reglas de coincidencia '?' y ' ':
'?' puede coincidir con cualquier carácter individual.
'
' puede coincidir con cualquier secuencia de caracteres (incluida la secuencia de caracteres vacía).
La condición necesaria y suficiente para una coincidencia exitosa es que el patrón de caracteres debe coincidir completamente con la cadena de entrada (en lugar de una coincidencia parcial).

Ideas para resolver problemas

Al analizar las ideas de resolución de problemas de cada versión, presentaremos en detalle los pasos del algoritmo de cada versión. Aquí están las ideas de resolución de problemas para cada versión:

Ir versión:

La versión Go de la idea de resolución de problemas consiste en utilizar punteros dobles y retroceder para hacer coincidir cadenas y patrones. Los pasos principales son los siguientes:

  1. Primero, use un bucle para procesar caracteres pconsecutivos *al final del patrón. Esto es para omitir la redundancia en el patrón *.

  2. Luego ingrese un bucle e itere a través de la cadena sy el patrón al mismo tiempo p:

    • Si el carácter del patrón actual es *, registre la posición de la cadena sy el patrón actuales py pmueva el puntero del patrón una posición hacia atrás.
    • Si el carácter actual coincide o es ?un carácter comodín, mueva los punteros de cadena y de patrón hacia atrás un bit.
    • Si los caracteres no coinciden y hay una posición de retroceso, retroceda a la *posición anterior y actualice los punteros de cadena y patrón.
  3. Una vez finalizado el ciclo, verifique si hay *caracteres sin procesar en el patrón p.

  4. Finalmente, verifique psi el patrón coincide exactamente con la cadena s. Si el puntero del patrón pllega al final del patrón, la coincidencia es exitosa.

Versión de Python:

Las ideas de resolución de problemas de la versión Python son similares a las de la versión Go, y también utilizan punteros dobles y retroceso. Los pasos principales son los siguientes:

  1. Primero, use un bucle para procesar caracteres pconsecutivos *al final del patrón. Esto es para omitir la redundancia en el patrón *.

  2. Luego ingrese un bucle e itere a través de la cadena sy el patrón al mismo tiempo p:

    • Si el carácter del patrón actual es *, registre la posición de la cadena sy el patrón actuales py pmueva el puntero del patrón una posición hacia atrás.
    • Si el carácter actual coincide o es ?un carácter comodín, mueva los punteros de cadena y de patrón hacia atrás un bit.
    • Si los caracteres no coinciden y hay una posición de retroceso, retroceda a la *posición anterior y actualice los punteros de cadena y patrón.
  3. Una vez finalizado el ciclo, verifique si hay *caracteres sin procesar en el patrón p.

  4. Finalmente, verifique psi el patrón coincide exactamente con la cadena s. Si el puntero del patrón pllega al final del patrón, la coincidencia es exitosa.

Versión de Java:

Las ideas de resolución de problemas de la versión Java también utilizan punteros dobles y retroceso. Los pasos principales son los siguientes:

  1. Primero, use un bucle para procesar caracteres pconsecutivos *al final del patrón. Esto es para omitir la redundancia en el patrón *.

  2. Luego ingrese un bucle e itere a través de la cadena sy el patrón al mismo tiempo p:

    • Si el carácter del patrón actual es *, registre la posición de la cadena sy el patrón actuales py pmueva el puntero del patrón una posición hacia atrás.
    • Si el carácter actual coincide o es ?un carácter comodín, mueva los punteros de cadena y de patrón hacia atrás un bit.
    • Si los caracteres no coinciden y hay una posición de retroceso, retroceda a la *posición anterior y actualice los punteros de cadena y patrón.
  3. Una vez finalizado el ciclo, verifique si hay *caracteres sin procesar en el patrón p.

  4. Finalmente, verifique psi el patrón coincide exactamente con la cadena s. Si el puntero del patrón pllega al final del patrón, la coincidencia es exitosa.

Versión C++:

Las ideas de resolución de problemas de la versión C++ son similares a las de otras versiones, y también utilizan punteros dobles y retroceso. Los pasos principales son los siguientes:

  1. Primero, use un bucle para procesar caracteres pconsecutivos *al final del patrón. Esto es para omitir la redundancia en el patrón *.

  2. Luego ingrese un bucle e itere a través de la cadena sy el patrón al mismo tiempo p:

    • Si el carácter del patrón actual es *, registre la posición de la cadena sy el patrón actuales py pmueva el puntero del patrón una posición hacia atrás.
    • Si el carácter actual coincide o es ?un carácter comodín, mueva los punteros de cadena y de patrón hacia atrás un bit.
    • Si los caracteres no coinciden y hay una posición de retroceso, retroceda a la *posición anterior y actualice los punteros de cadena y patrón.
  3. Una vez finalizado el ciclo, verifique si hay *caracteres sin procesar en el patrón p.

  4. Finalmente, verifique psi el patrón coincide exactamente con la cadena s. Si el puntero del patrón pllega al final del patrón, la coincidencia es exitosa.

En general, no importa qué lenguaje de programación utilice, la idea central de la solución son los punteros dobles y el retroceso para hacer coincidir cadenas y patrones, mientras maneja comodines *y ?.

código

func isMatch(s string, p string) bool {
    
    
    // 进入循环,只要s和p非空且p的最后一个字符不是'*'
    for len(s) > 0 && len(p) > 0 && p[len(p)-1] != '*' {
    
    
        // 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
        if charMatch(s[len(s)-1], p[len(p)-1]) {
    
    
            s = s[:len(s)-1]
            p = p[:len(p)-1]
        } else {
    
    
            // 如果字符不匹配,返回false
            return false
        }
    }
    // 如果p为空,返回s是否也为空
    if len(p) == 0 {
    
    
        return len(s) == 0
    }
    // 初始化索引和记录变量
    sIndex, pIndex := 0, 0
    sRecord, pRecord := -1, -1
    // 开始循环,sIndex小于s的长度且pRecord小于p的长度
    for sIndex < len(s) && pRecord < len(p) {
    
    
        // 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
        if p[pIndex] == '*' {
    
    
            pIndex++
            sRecord, pRecord = sIndex, pIndex
        } else if charMatch(s[sIndex], p[pIndex]) {
    
    
            // 如果字符匹配,将s和p的索引都向后移动
            sIndex++
            pIndex++
        } else if sRecord != -1 && sRecord + 1 < len(s) {
    
    
            // 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
            sRecord++
            sIndex, pIndex = sRecord, pRecord
        } else {
    
    
            // 如果没有符合的情况,返回false
            return false
        }
    }
    // 最后,检查p中是否只包含'*'
    return allStars(p, pIndex, len(p))
}

// 辅助函数,检查字符串中是否都是'*'
func allStars(str string, left, right int) bool {
    
    
    for i := left; i < right; i++ {
    
    
        if str[i] != '*' {
    
    
            return false
        }
    }
    return true
}

// 辅助函数,检查两个字符是否匹配
func charMatch(u, v byte) bool {
    
    
    return u == v || v == '?'
}

Pitón

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        # 进入循环,只要s和p非空且p的最后一个字符不是'*'
        while s and p and p[-1] != '*':
            # 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
            if self.charMatch(s[-1], p[-1]):
                s = s[:-1]
                p = p[:-1]
            else:
                # 如果字符不匹配,返回false
                return False
        # 如果p为空,返回s是否也为空
        if not p:
            return not s
        # 初始化索引和记录变量
        sIndex, pIndex = 0, 0
        sRecord, pRecord = -1, -1
        # 开始循环,sIndex小于s的长度且pRecord小于p的长度
        while sIndex < len(s) and pRecord < len(p):
            # 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
            if p[pIndex] == '*':
                pIndex += 1
                sRecord, pRecord = sIndex, pIndex
            elif self.charMatch(s[sIndex], p[pIndex]):
                # 如果字符匹配,将s和p的索引都向后移动
                sIndex += 1
                pIndex += 1
            elif sRecord != -1 and sRecord + 1 < len(s):
                # 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
                sRecord += 1
                sIndex, pIndex = sRecord, pRecord
            else:
                # 如果没有符合的情况,返回false
                return False
        # 最后,检查p中是否只包含'*'
        return self.allStars(p, pIndex, len(p))

    # 辅助函数,检查字符串中是否都是'*'
    def allStars(self, s, left, right):
        for i in range(left, right):
            if s[i] != '*':
                return False
        return True

    # 辅助函数,检查两个字符是否匹配
    def charMatch(self, u, v):
        return u == v or v == '?'

Java

class Solution {
    public boolean isMatch(String s, String p) {
        // 进入循环,只要s和p非空且p的最后一个字符不是'*'
        while (s.length() > 0 && p.length() > 0 && p.charAt(p.length() - 1) != '*') {
            // 如果字符匹配或者p的最后一个字符是'?',则从s和p的末尾去掉一个字符
            if (charMatch(s.charAt(s.length() - 1), p.charAt(p.length() - 1))) {
                s = s.substring(0, s.length() - 1);
                p = p.substring(0, p.length() - 1);
            } else {
                // 如果字符不匹配,返回false
                return false;
            }
        }
        // 如果p为空,返回s是否也为空
        if (p.length() == 0) {
            return s.length() == 0;
        }
        // 初始化索引和记录变量
        int sIndex = 0, pIndex = 0;
        int sRecord = -1, pRecord = -1;
        // 开始循环,sIndex小于s的长度且pRecord小于p的长度
        while (sIndex < s.length() && pRecord < p.length()) {
            // 如果p的当前字符是'*',将p的索引向后移动,记录s和p的位置
            if (p.charAt(pIndex) == '*') {
                pIndex++;
                sRecord = sIndex;
                pRecord = pIndex;
            } else if (charMatch(s.charAt(sIndex), p.charAt(pIndex))) {
                // 如果字符匹配,将s和p的索引都向后移动
                sIndex++;
                pIndex++;
            } else if (sRecord != -1 && sRecord + 1 < s.length()) {
                // 如果字符不匹配,但是有记录的位置可用,并且sRecord+1小于s的长度,更新sIndex和pIndex
                sRecord++;
                sIndex = sRecord;
                pIndex = pRecord;
            } else {
                // 如果没有符合的情况,返回false
                return false;
            }
        }
        // 最后,检查p中是否只包含'*'
        return allStars(p, pIndex, p.length());
    }

    // 辅助函数,检查字符串中是否都是'*'
    private boolean allStars(String str, int left, int right) {
        for (int i = left; i < right; i++) {
            if (str.charAt(i) != '*') {
                return false;
            }
        }
        return true;
    }

    // 辅助函数,检查两个字符是否匹配
    private boolean charMatch(char u, char v) {
        return u == v || v == '?';
    }
}

cpp

class Solution {
public:
    bool isMatch(string s, string p) {
        int lens = s.size(); // 获取字符串s的长度
        int lenp = p.size(); // 获取模式p的长度
        int scur = 0; // 初始化字符串s的当前指针
        int sstar = -1; // 初始化字符串s的'*'的位置记录
        int pcur = 0; // 初始化模式p的当前指针
        int pstar = -1; // 初始化模式p的'*'的位置记录
        
        while (scur < lens) { // 循环处理字符串s
            if (pcur < lenp && p[pcur] == '*') { // 如果模式p当前字符是'*'
                sstar = scur; // 记录当前字符串s的位置
                pstar = ++pcur; // 记录当前模式p的位置,同时将模式p指针向后移动
            } else {
                if (pcur < lenp && (p[pcur] == '?' || p[pcur] == s[scur])) {
                    // 如果模式p当前字符是'?'或者与字符串s当前字符相匹配
                    scur++; // 移动字符串s的指针
                    pcur++; // 移动模式p的指针
                } else {
                    if (sstar < 0) return false; // 如果没有'*'的位置记录,返回false
                    scur = ++sstar; // 回溯到'*'的位置的下一个字符
                    pcur = pstar; // 恢复模式p的指针到'*'的位置的下一个字符
                }
            }
        }
        
        while (pcur < lenp && p[pcur] == '*') pcur++; // 处理模式p中多余的'*'
        
        return pcur == lenp; // 返回是否模式p已经处理完毕
    }
};

Detallaremos los conceptos básicos necesarios al analizar cada versión de la solución. Primero, usaremos versiones de Go, Python, Java y C++ para el análisis.

Ir versión:

  1. Sintaxis básica y tipos de datos : en Go, debe comprender la sintaxis básica y los tipos de datos, incluidas declaraciones de variables, bucles, declaraciones condicionales, etc.

  2. Operaciones de cadena : necesita saber cómo procesar cadenas, incluidas las operaciones de corte de cadenas y obtener la longitud de una cadena.

  3. Bucles y declaraciones condicionales : los bucles y las declaraciones condicionales se utilizan en el código para iterar a través de cadenas y realizar diferentes operaciones, por lo que es necesario comprender estas estructuras de control.

  4. Operación de corte : en Go, la operación de corte es una de las operaciones clave para procesar cadenas y matrices. Necesita saber cómo interceptar y manipular cortes.

Versión de Python:

  1. Sintaxis básica y tipos de datos : en Python, es necesario comprender la sintaxis básica y los tipos de datos, incluidas variables, listas, cadenas, bucles, declaraciones condicionales, etc.

  2. Operación de cadenas : Python proporciona una gran cantidad de métodos de operación de cadenas, que incluyen corte, empalme, longitud, etc. Es necesario comprender estas operaciones.

  3. Bucles y declaraciones condicionales : los bucles y las declaraciones condicionales se utilizan en el código para iterar a través de cadenas y realizar diferentes operaciones, por lo que es necesario comprender estas estructuras de control.

  4. Programación orientada a objetos (POO) : aunque no se utilizan clases ni objetos en el código, Python es un lenguaje de programación orientado a objetos, por lo que es necesario comprender los conceptos básicos de la POO.

Versión de Java:

  1. Sintaxis básica y tipos de datos : en Java, necesita conocer la sintaxis básica y los tipos de datos, incluida la declaración de variables, lista, cadena, bucle, declaración condicional, etc.

  2. Operaciones de cadena : Java proporciona clases y métodos para procesar cadenas, es necesario comprender cómo utilizar Stringmétodos de clase para operar cadenas.

  3. Bucles y declaraciones condicionales : los bucles y las declaraciones condicionales se utilizan en el código para iterar a través de cadenas y realizar diferentes operaciones, por lo que es necesario comprender estas estructuras de control.

  4. Programación orientada a objetos (POO) : Java es un lenguaje de programación orientado a objetos y es necesario comprender los conceptos básicos de la POO, es decir, clases, objetos, herencia, etc.

Versión C++:

  1. Sintaxis básica y tipos de datos : en C++, es necesario comprender la sintaxis básica y los tipos de datos, incluidas declaraciones de variables, matrices, cadenas, bucles, declaraciones condicionales, etc.

  2. Operaciones de cadena : C ++ proporciona una biblioteca estándar para procesar cadenas. Necesita saber cómo usar las funciones de cadena en la biblioteca estándar para operar cadenas.

  3. Bucles y declaraciones condicionales : los bucles y las declaraciones condicionales se utilizan en el código para iterar a través de cadenas y realizar diferentes operaciones, por lo que es necesario comprender estas estructuras de control.

  4. Punteros y referencias : C++ implica los conceptos de punteros y referencias, especialmente cuando se trata de cadenas. Es necesario comprender cómo utilizar punteros y referencias para manipular datos.

En general, no importa qué versión del lenguaje de programación elija, debe dominar los conceptos básicos de programación, las estructuras de control, los métodos de manipulación de cadenas y comprender e implementar algoritmos basados ​​en características específicas del lenguaje. Cada versión utiliza conocimientos básicos de programación, como bucles, declaraciones condicionales y manipulación de cadenas para resolver problemas de coincidencia de comodines.

45. Juego de salto II

tema

Dada una matriz de números enteros no negativos nums, inicialmente se ubicará en el primer índice de la matriz.

Cada elemento de la matriz representa la longitud máxima de salto en esa posición.

Tu objetivo es llegar al último índice en el número mínimo de saltos.

Puedes asumir que siempre puedes llegar al último índice.

Ejemplo 1:

Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.

Ejemplo 2:

Input: nums = [2,3,0,1,4]
Output: 2

Restricciones:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 10^5

La idea general del tema.

Dada una matriz de números enteros no negativos, inicialmente se encuentra en la primera posición de la matriz. Cada elemento de la matriz representa la longitud máxima que puede saltar en esa posición. Su objetivo es llegar a la última posición de la matriz utilizando la menor cantidad de saltos.

Ideas para resolver problemas

  • Si se le pide que encuentre el número mínimo de saltos, naturalmente pensará en utilizar un algoritmo codicioso para resolver el problema. Escanee la matriz de pasos, mantenga la posición actual que puede alcanzar el subíndice máximo y regístrela como el límite más lejano que se puede alcanzar. Si se alcanza el límite más lejano durante el proceso de escaneo, actualice el límite y aumente el número de saltos en 1 .
  • Al escanear la matriz, en realidad no es necesario escanear el último elemento, porque antes de saltar al último elemento, el límite más lejano que se puede alcanzar debe ser mayor o igual que la posición del último elemento; de lo contrario, el último elemento no se saltará y no se alcanzará el punto final.; Si se atraviesa el último elemento, significa que el límite es exactamente la última posición, y el número final de saltos puede ser directamente + 1, y no hay necesidad de acceder el último elemento.

Ir a la versión de ideas para resolver problemas

En la versión Go, la idea para resolver el problema "Jump Game II" es la siguiente:

  1. Inicialice tres variables: needChoose(que indica la ubicación donde debe elegir el siguiente paso), canReach(que indica la posición más lejana que se puede alcanzar actualmente), step(que indica el número de pasos a saltar) e inicialícelas todas a 0.

  2. Para iterar sobre la matriz de entrada nums, utilice for i, x := range numspara atravesar.

  3. Durante el proceso de recorrido, verifique si la posición actual imás la distancia máxima que se puede saltar es mayor que , de ser así, actualice a , indicando la posición adicional que se puede alcanzar.xcanReachcanReachi + x

  4. Si canReachya es mayor o igual que la última posición de la matriz len(nums)-1, regrese directamente step + 1porque se alcanzó el punto final.

  5. Si la posición actual ies igual a needChoosela posición señalada, significa que debe seleccionar la siguiente posición. En este momento, needChooseactualice a canReach, lo que indica que el siguiente paso comenzará canReachdesde , y stepagregue 1 a , lo que indica que se ha saltado un paso.

  6. Finalmente se devuelve el número mínimo de pasos step, que es el número mínimo de saltos necesarios para llegar a la última posición.

Ideas para resolver problemas de la versión Python

En la versión Python, la idea de resolver el problema "Jump Game II" es similar a la versión Go:

  1. Inicialice tres variables: needChoose(que indica la ubicación donde debe elegir el siguiente paso), canReach(que indica la posición más lejana que se puede alcanzar actualmente), step(que indica el número de pasos a saltar) e inicialícelas todas a 0.

  2. Para iterar sobre la lista de entrada nums, utilice for i in range(len(nums))para recorrer.

  3. Durante el proceso de recorrido, verifique si la posición actual imás la distancia máxima que se puede saltar es mayor que , de ser así, actualice a , indicando la posición adicional que se puede alcanzar.nums[i]canReachcanReachi + nums[i]

  4. Si canReachya es mayor o igual que la última posición de la lista len(nums)-1, regrese directamente step + 1porque se alcanzó el punto final.

  5. Si la posición actual ies igual a needChoosela posición señalada, significa que debe seleccionar la siguiente posición. En este momento, needChooseactualice a canReach, lo que indica que el siguiente paso comenzará canReachdesde , y stepagregue 1 a , lo que indica que se ha saltado un paso.

  6. Finalmente se devuelve el número mínimo de pasos step, que es el número mínimo de saltos necesarios para llegar a la última posición.

Ideas para resolver problemas de la versión Java

En la versión Java, la idea de resolver el problema "Jump Game II" es similar a la de las versiones Go y Python:

  1. Inicialice tres variables: needChoose(que indica la ubicación donde debe elegir el siguiente paso), canReach(que indica la posición más lejana que se puede alcanzar actualmente), step(que indica el número de pasos a saltar) e inicialícelas todas a 0.

  2. Para iterar sobre la matriz de entrada nums, utilice for (int i = 0; i < nums.length; i++)para atravesar.

  3. Durante el proceso de recorrido, verifique si la posición actual imás la distancia máxima que se puede saltar es mayor que , de ser así, actualice a , indicando la posición adicional que se puede alcanzar.nums[i]canReachcanReachi + nums[i]

  4. Si canReachya es mayor o igual que la última posición de la matriz nums.length - 1, regrese directamente step + 1porque se alcanzó el punto final.

  5. Si la posición actual ies igual a needChoosela posición señalada, significa que debe seleccionar la siguiente posición. En este momento, needChooseactualice a canReach, lo que indica que el siguiente paso comenzará canReachdesde , y stepagregue 1 a , lo que indica que se ha saltado un paso.

  6. Finalmente se devuelve el número mínimo de pasos step, que es el número mínimo de saltos necesarios para llegar a la última posición.

Ideas para resolver problemas de la versión C ++

En la versión C ++, la idea de resolver el problema "Jump Game II" es similar a la versión anterior:

  1. Inicialice tres variables: needChoose(que indica la ubicación donde debe elegir el siguiente paso), canReach(que indica la posición más lejana que se puede alcanzar actualmente), step(que indica el número de pasos a saltar) e inicialícelas todas a 0.

  2. Para iterar sobre el vector de entrada nums, utilicefor (int i = 0; i < nums.size(); i++)

  3. Durante el proceso de recorrido, verifique si la posición actual imás la distancia máxima que se puede saltar es mayor que , de ser así, actualice a , indicando la posición adicional que se puede alcanzar.nums[i]canReachcanReachi + nums[i]

  4. Si canReachya es mayor o igual que la última posición del vector nums.size() - 1, entonces regresa directamente step + 1porque se ha alcanzado el punto final.

  5. Si la posición actual ies igual a needChoosela posición señalada, significa que debe seleccionar la siguiente posición. En este momento, needChooseactualice a canReach, lo que indica que el siguiente paso comenzará canReachdesde , y stepagregue 1 a , lo que indica que se ha saltado un paso.

  6. Finalmente se devuelve el número mínimo de pasos step, que es el número mínimo de saltos necesarios para llegar a la última posición.

Esta es la idea de solución para cada versión.

código

func jump(nums []int) int {
    
    
    // 如果数组长度为1,无需跳跃,返回0
    if len(nums) == 1 {
    
    
        return 0
    }
    // needChoose 表示需要选择下一步的位置,canReach 表示当前可以到达的最远位置,step 表示跳跃的步数
    needChoose, canReach, step := 0, 0, 0
    // 遍历数组
    for i, x := range nums {
    
    
        // 如果当前位置加上跳跃力可以到达更远的位置
        if i+x > canReach {
    
    
            // 更新 canReach 为更远的位置
            canReach = i + x
            // 如果 canReach 已经可以到达数组末尾,返回步数加1
            if canReach >= len(nums)-1 {
    
    
                return step + 1
            }
        }
        // 如果当前位置已经是 needChoose 所指的位置
        if i == needChoose {
    
    
            // 更新 needChoose 为 canReach,表示下一步要从 canReach 开始跳跃
            needChoose = canReach
            // 步数加1
            step++
        }
    }
    // 返回最小步数
    return step
}

Pitón

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        needChoose, canReach, step = 0, 0, 0
        for i in range(len(nums)):
            if i + nums[i] > canReach:
                canReach = i + nums[i]
                if canReach >= len(nums) - 1:
                    return step + 1
            if i == needChoose:
                needChoose = canReach
                step += 1
        return step

Java

class Solution {
    public int jump(int[] nums) {
        if (nums.length == 1) {
            return 0;
        }
        int needChoose = 0, canReach = 0, step = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i + nums[i] > canReach) {
                canReach = i + nums[i];
                if (canReach >= nums.length - 1) {
                    return step + 1;
                }
            }
            if (i == needChoose) {
                needChoose = canReach;
                step++;
            }
        }
        return step;
    }
}

cpp

class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) {
            return 0;
        }
        int needChoose = 0, canReach = 0, step = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (i + nums[i] > canReach) {
                canReach = i + nums[i];
                if (canReach >= nums.size() - 1) {
                    return step + 1;
                }
            }
            if (i == needChoose) {
                needChoose = canReach;
                step++;
            }
        }
        return step;
    }
};

Conocimientos básicos necesarios para cada versión del código.

Ir versión

  • Go (también conocido como Golang) es un lenguaje de programación de código abierto con una sintaxis concisa y un rendimiento eficiente. En esta versión Go del código, necesita conocer los siguientes conceptos básicos:
    • La sintaxis básica de Go, incluida la declaración de variables, bucles, declaraciones condicionales, etc.
    • El uso de sectores y matrices porque la pregunta implica procesar matrices de números enteros.
    • Definición y llamada de funciones, así como procesamiento de parámetros de funciones y valores de retorno.
    • Uso de estructuras de bucle (bucles for) y declaraciones condicionales (declaraciones if), ya que son importantes a la hora de resolver problemas.
    • Operaciones de corte, como expansión de corte, acceso a índice, etc., porque están relacionadas con problemas de salto.

Versión de Python

  • Python es un lenguaje de programación de alto nivel ampliamente utilizado conocido por su sintaxis simple y fácil de leer. En esta versión Python del código, necesita conocer los siguientes conceptos básicos:
    • La sintaxis básica de Python, incluidas declaraciones de variables, bucles, declaraciones condicionales, etc.
    • El uso de listas (List), porque la pregunta implica procesar listas de números enteros.
    • Definición de clases y métodos porque el código utiliza clases para organizar la solución.
    • Uso de estructuras de bucle (bucles for) y declaraciones condicionales (declaraciones if), ya que son importantes a la hora de resolver problemas.

versión java

  • Java es un lenguaje de programación de tipo estático ampliamente utilizado, que a menudo se utiliza para crear aplicaciones a gran escala. En esta versión Java del código, necesita conocer los siguientes conceptos básicos:
    • Sintaxis básica de Java, incluida declaración de variables, bucles, declaraciones condicionales, etc.
    • El uso de matrices porque la pregunta implica procesar matrices de números enteros.
    • Definición de clases y métodos porque el código utiliza clases para organizar la solución.
    • Uso de estructuras de bucle (bucles for) y declaraciones condicionales (declaraciones if), ya que son importantes a la hora de resolver problemas.

versión C++

  • C++ es un lenguaje de programación multiparadigma que combina características de programación de alto y bajo nivel. En esta versión C++ del código, necesita conocer los siguientes conceptos básicos:
    • Sintaxis básica de C++, incluida declaración de variables, bucles, declaraciones condicionales, etc.
    • El uso de vector (Vector), porque la pregunta implica procesar vectores enteros.
    • Definición de clases y métodos porque el código utiliza clases para organizar la solución.
    • Uso de estructuras de bucle (bucles for) y declaraciones condicionales (declaraciones if), ya que son importantes a la hora de resolver problemas.

Lo anterior es una descripción general de los conceptos básicos necesarios para cada versión del código. Si necesita una explicación más detallada o tiene preguntas específicas, no dude en preguntar.

46. ​​Permutaciones

tema

Dada una colección de números enteros distintos , devuelve todas las permutaciones posibles.

Ejemplo:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

La idea general del tema.

Dada una secuencia sin números repetidos, devuelve todas las permutaciones posibles de la misma.

Ideas para resolver problemas

  • Para encontrar todas las permutaciones en las permutaciones y combinaciones de una matriz, simplemente use DFS para buscar en profundidad.

Vaya a la versión de ideas para resolver problemas:

  1. Búsqueda en profundidad (DFS): esta solución utiliza un algoritmo de búsqueda en profundidad para generar todas las permutaciones posibles.

  2. Función recursiva DFS: En dfsla función mantenemos dos parámetros importantes: pathy visited. pathAlmacena la permutación actual que se está generando, visitedmarcando qué números se han utilizado.

  3. Proceso recursivo: en cada llamada recursiva, intentamos agregar números no utilizados pathy marcarlos como usados. Luego, dfsla función se llama de forma recursiva para continuar generando el siguiente número. La condición final de la recursividad es pathque la longitud de sea igual a numsla longitud de la matriz de entrada, lo que indica que se ha generado una permutación completa.

  4. Retroceso: cuando regresa la recursividad, debemos retroceder al nivel de estado anterior. Esto implica eliminar el último pathnúmero agregado y marcar su correspondiente visitedcomo no utilizado para que se puedan probar otros números en la siguiente iteración.

  5. Colección de resultados: cada vez que encontramos una permutación completa, la copiamos en un conjunto de resultados ( ans), y eventualmente devolvemos todas las permutaciones.

Ideas para resolver problemas de la versión Python:

  1. Búsqueda en profundidad primero (DFS): esta solución también utiliza un algoritmo de búsqueda en profundidad para generar todas las permutaciones posibles.

  2. Función recursiva DFS: En trackbackla función mantenemos tres parámetros importantes: currla permutación que se está generando actualmente, usedel índice del número que se ha utilizado numsy la matriz de entrada.

  3. Proceso recursivo: en cada llamada recursiva, recorremos los números no utilizados (verificando usedla lista), los agregamos curry agregamos el índice correspondiente used. Luego, trackbackla función se llama de forma recursiva para continuar generando el siguiente número. La condición final de la recursividad es currque la longitud de sea igual a numsla longitud de la matriz de entrada, lo que indica que se ha generado una permutación completa.

  4. Retroceso: cuando regresa la recursividad, debemos retroceder al nivel de estado anterior. Esto implica eliminar el último currnúmero agregado y usedeliminar para poder probar otros números en la siguiente iteración.

  5. Colección de resultados: cada vez que encontramos una permutación completa, la agregamos al conjunto de resultados y, finalmente, devolvemos todas las permutaciones.

Ideas de solución de la versión Java:

  1. Búsqueda en profundidad primero (DFS): esta solución también utiliza un algoritmo de búsqueda en profundidad para generar todas las permutaciones posibles.

  2. Función recursiva DFS: en dfsla función, mantenemos tres parámetros importantes: numsuna matriz de entrada que pathalmacena el arreglo que se está generando actualmente visitedy una matriz booleana que marca qué números se han utilizado.

  3. Proceso recursivo: en cada llamada recursiva, recorremos los números no utilizados, los sumamos pathy los marcamos como usados. Luego, dfsla función se llama de forma recursiva para continuar generando el siguiente número. La condición final de la recursividad es pathque la longitud de sea igual a numsla longitud de la matriz de entrada, lo que indica que se ha generado una permutación completa.

  4. Retroceso: cuando regresa la recursividad, debemos retroceder al nivel de estado anterior. Esto implica eliminar el último pathnúmero agregado y marcar su índice correspondiente visitedcomo no utilizado para poder probar otros números en la siguiente iteración.

  5. Colección de resultados: cada vez que encontramos una permutación completa, la agregamos al conjunto de resultados ( ans), y eventualmente devolvemos todas las permutaciones.

Ideas para resolver problemas de la versión C ++:

  1. Búsqueda en profundidad primero (DFS): esta solución también utiliza un algoritmo de búsqueda en profundidad para generar todas las permutaciones posibles.

  2. Función recursiva DFS: en dfsla función, mantenemos cuatro parámetros importantes: numsuna matriz de entrada para currentPermutationalmacenar la permutación que se está generando actualmente, visiteduna matriz booleana para marcar qué números se han utilizado y una matriz booleana anspara almacenar los resultados de todas las permutaciones.

  3. Proceso recursivo: en cada llamada recursiva, recorremos los números no utilizados, los sumamos currentPermutationy los marcamos como usados. Luego, dfsla función se llama de forma recursiva para continuar generando el siguiente número. La condición final de la recursividad es currentPermutationque la longitud de sea igual a numsla longitud de la matriz de entrada, lo que indica que se ha generado una permutación completa.

  4. Retroceso: cuando regresa la recursividad, debemos retroceder al nivel de estado anterior. Esto implica eliminar el último currentPermutationnúmero agregado y marcar su índice correspondiente visitedcomo no utilizado para poder probar otros números en la siguiente iteración.

  5. Colección de resultados: cada vez que encontramos una permutación completa, la agregamos ansal y, finalmente, devolvemos todas las permutaciones.

código

Ir

func permute(nums []int) [][]int {
    var ans [][]int
    var dfs func(path []int, visited []bool)

    dfs = func(path []int, visited []bool) {
        if len(path) == len(nums) {
            temp := make([]int, len(path))
            copy(temp, path)
            ans = append(ans, temp)
            return
        }

        for i := 0; i < len(nums); i++ {
            if visited[i] {
                continue
            }
            path = append(path, nums[i])
            visited[i] = true
            dfs(path, visited)
            visited[i] = false
            path = path[:len(path)-1]
        }
    }

    visited := make([]bool, len(nums))
    dfs([]int{}, visited)
    return ans
}

Pitón

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        self.trackback([], [], nums, res)
        return res
        
    def trackback(self, curr, used, nums, res):
        if len(curr) == len(nums):
            res.append(curr)
            return
        else:
            for i in range(len(nums)):
                if i not in used:
                    self.trackback(curr+[nums[i]], used+[i], nums, res)

Java

class Solution {
    List<List<Integer>> ans;  // 用于存储所有全排列的结果
    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<>();
        boolean[] visited = new boolean[nums.length];  // 用于标记数字是否已经被访问
        dfs(nums, new ArrayList<Integer>(), visited);  // 调用深度优先搜索函数
        return ans;  // 返回所有全排列的结果
    }

    public void dfs(int[] nums, List<Integer> path, boolean[] visited) {
        if (path.size() == nums.length) {  // 如果当前路径的长度等于数组长度,表示找到了一个全排列
            ans.add(new ArrayList<>(path));  // 将当前路径加入结果集
            return;  // 返回上一层继续搜索
        }

        for (int i = 0; i < nums.length; i++) {
            if (visited[i]) {
                continue;  // 如果数字已经被访问过,则跳过
            }
            path.add(nums[i]);  // 将数字加入当前路径
            visited[i] = true;  // 标记数字已经被访问
            dfs(nums, path, visited);  // 递归搜索下一层
            visited[i] = false;  // 恢复标记,以便尝试其他可能的数字
            path.remove(path.size() - 1);  // 移除最后一个数字,回溯到上一层状态
        }
    }
}

cpp

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> currentPermutation;
        vector<bool> visited(nums.size(), false);

        dfs(nums, currentPermutation, visited, ans);

        return ans;
    }

    void dfs(vector<int>& nums, vector<int>& currentPermutation, vector<bool>& visited, vector<vector<int>>& ans) {
        if (currentPermutation.size() == nums.size()) {
            ans.push_back(currentPermutation);
            return;
        }

        for (int i = 0; i < nums.size(); i++) {
            if (!visited[i]) {
                currentPermutation.push_back(nums[i]);
                visited[i] = true;
                dfs(nums, currentPermutation, visited, ans);
                visited[i] = false;
                currentPermutation.pop_back();
            }
        }
    }
};

Conocimientos básicos que necesitas dominar en cada versión:

Ir versión:

  1. Conocimientos básicos :

    • La sintaxis básica del lenguaje Go, incluidas variables, funciones, bucles, declaraciones condicionales, etc.
    • Slice: matriz de longitud variable en Go, utilizada para almacenar datos dinámicamente.
    • Recursividad: comprenda el concepto y el uso de la recursividad, tal como se utiliza aquí para generar permutaciones completas.
  2. DFS (primera búsqueda en profundidad) :

    • Comprenda cómo funciona el algoritmo de búsqueda en profundidad, un enfoque común para resolver problemas de combinación y permutación.
    • Cómo se mantiene el estado en funciones recursivas, incluidas rutas y tokens de acceso.

Versión de Python:

  1. Conocimientos básicos :

    • La sintaxis básica de Python, incluidas listas, bucles, declaraciones condicionales, etc.
    • Lista: una secuencia mutable en Python utilizada para almacenar múltiples elementos.
    • Recursividad: comprenda el concepto y el uso de la recursividad, tal como se utiliza aquí para generar permutaciones completas.
  2. DFS (primera búsqueda en profundidad) :

    • Comprenda cómo funciona el algoritmo de búsqueda en profundidad, un enfoque común para resolver problemas de combinación y permutación.
    • Cómo mantener el estado en una función recursiva, incluida la disposición actual, la lista de elementos utilizados, etc.

Versión de Java:

  1. Conocimientos básicos :

    • Sintaxis básica del lenguaje Java, incluidas clases, métodos, matrices, bucles, declaraciones condicionales, etc.
    • Lista: una clase de colección en Java, utilizada para almacenar múltiples elementos.
    • Recursividad: comprenda el concepto y el uso de la recursividad, tal como se utiliza aquí para generar permutaciones completas.
  2. DFS (primera búsqueda en profundidad) :

    • Comprenda cómo funciona el algoritmo de búsqueda en profundidad, un enfoque común para resolver problemas de combinación y permutación.
    • Cómo mantener el estado en una función recursiva, incluida la disposición actual, una matriz etiquetada de elementos usados, etc.

Versión C++:

  1. Conocimientos básicos :

    • Sintaxis básica de C++, incluidas clases, funciones, matrices, bucles, declaraciones condicionales, etc.
    • Vector: una matriz de longitud variable en C++, utilizada para almacenar múltiples elementos.
    • Recursividad: comprenda el concepto y el uso de la recursividad, tal como se utiliza aquí para generar permutaciones completas.
  2. DFS (primera búsqueda en profundidad) :

    • Comprenda cómo funciona el algoritmo de búsqueda en profundidad, un enfoque común para resolver problemas de combinación y permutación.
    • Cómo mantener el estado en una función recursiva, incluida la disposición actual, una matriz etiquetada de elementos usados, etc.

Independientemente de la versión que elija, comprender los conceptos de búsqueda en profundidad y recursividad es clave. Todos estos ejemplos de código muestran cómo utilizar la búsqueda en profundidad para resolver problemas de permutación, donde la recursividad es la forma principal de pensar. Al mismo tiempo, también es importante comprender la sintaxis y las estructuras de datos de cada lenguaje de programación, ya que pueden implementarse de manera diferente en distintos lenguajes.

47. Permutaciones II

tema

Dada una colección de números que pueden contener duplicados, devuelve todas las permutaciones únicas posibles.

Ejemplo:

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

La idea general del tema.

Dada una secuencia que puede contener números repetidos, devuelve todas las permutaciones que no se repiten.

Ideas para resolver problemas

  • Esta pregunta es una versión mejorada de la pregunta 46. En la pregunta 46, se encuentra la disposición de la matriz. Los elementos de la matriz no se repiten. Sin embargo, en esta pregunta, los elementos de la matriz se repiten, por lo que el resultado final ordenado debe ser deduplicado.
  • El método de deduplicación es la lógica clásica: después de ordenar la matriz, se determinan los elementos duplicados y luego se realiza un juicio lógico.
  • Las otras ideas son exactamente las mismas que las de la pregunta 46, solo haga una búsqueda profunda con DFS.

Vaya a la versión de ideas para resolver problemas:

  1. Ordenar matriz: primero, ordene la matriz de enteros de entrada nums. Este paso es fundamental porque reúne elementos duplicados para preparar la lógica de deduplicación posterior.

  2. Búsqueda en profundidad (DFS): utiliza un algoritmo de búsqueda en profundidad para generar permutaciones de forma recursiva. De principio a fin, considere si los elementos de la matriz se pueden agregar uno por uno a la disposición actual.

  3. Lógica de deduplicación: en el proceso de generación recursiva de un arreglo, es necesario determinar si el elemento actual se puede agregar al arreglo para evitar la duplicación. Si el elemento actual es el mismo que el elemento anterior y el elemento anterior no se utiliza, el elemento actual se omite para evitar que se repita la disposición.

  4. Colección de resultados: cada vez que se genera una permutación completa, se agrega al conjunto de resultados. Finalmente, se devuelve el conjunto de resultados.

Ideas para resolver problemas de la versión Python:

  1. Matriz ordenada: nuevamente, la matriz de entrada de números enteros se numsordena primero para manejar elementos duplicados.

  2. Búsqueda en profundidad (DFS): utiliza un algoritmo de búsqueda en profundidad para generar permutaciones de forma recursiva. Durante el proceso recursivo, se agregan elementos continuamente a la disposición actual.

  3. Lógica de deduplicación: en el proceso de generación recursiva del arreglo, se evita la duplicación determinando si el elemento se ha utilizado y si es el mismo que el elemento anterior y el elemento anterior no se ha utilizado.

  4. Colección de resultados: cada vez que se genera una permutación completa, se agrega a la lista de resultados. Finalmente, se devuelve una lista de resultados.

Ideas de solución de la versión Java:

  1. Ordenar matriz: ordena la matriz de entrada de números enteros nums, lo que ayuda con elementos duplicados.

  2. Búsqueda en profundidad (DFS): utiliza un algoritmo de búsqueda en profundidad para generar permutaciones de forma recursiva. Durante el proceso recursivo, se agregan elementos continuamente a la disposición actual.

  3. Lógica de deduplicación: en el proceso de generación recursiva del arreglo, se evita la duplicación determinando si el elemento se ha utilizado y si es el mismo que el elemento anterior y el elemento anterior no se ha utilizado.

  4. Colección de resultados: cada vez que se genera una permutación completa, se agrega a la lista de resultados. Finalmente, se devuelve una lista de resultados.

Ideas para resolver problemas de la versión C ++:

  1. Matriz ordenada: nuevamente, la matriz de entrada de números enteros numsse ordena para manejar elementos duplicados.

  2. Búsqueda en profundidad (DFS): utiliza un algoritmo de búsqueda en profundidad para generar permutaciones de forma recursiva. Durante el proceso recursivo, se agregan elementos continuamente a la disposición actual.

  3. Lógica de deduplicación: en el proceso de generación recursiva del arreglo, se evita la duplicación determinando si el elemento se ha utilizado y si es el mismo que el elemento anterior y el elemento anterior no se ha utilizado.

  4. Colección de resultados: cada vez que se genera una permutación completa, se agrega al vector de resultados. Finalmente, se devuelve el vector resultante.

En general, las ideas de resolución de problemas de estas cuatro versiones se basan en la búsqueda en profundidad (DFS) y la lógica de deduplicación, que generan arreglos y evitan la duplicación al agregar y eliminar elementos continuamente. Ordenar la matriz es un paso de preprocesamiento clave para garantizar que los mismos elementos estén juntos para el juicio de deduplicación. Estas ideas son métodos generales para resolver problemas de permutación. Cuando se trata de situaciones que contienen elementos repetidos, se debe tener mucho cuidado para eliminar duplicados.

código

Ir

import "sort"

func permuteUnique(nums []int) [][]int {
    if len(nums) == 0 {
        return [][]int{}
    }
    used, p, res := make([]bool, len(nums)), []int{}, [][]int{}
    sort.Ints(nums) // 对输入数组进行排序,关键的去重逻辑
    generatePermutation47(nums, 0, p, &res, &used)
    return res
}

func generatePermutation47(nums []int, index int, p []int, res *[][]int, used *[]bool) {
    if index == len(nums) {
        temp := make([]int, len(p))
        copy(temp, p)
        *res = append(*res, temp) // 将当前排列添加到结果集中
        return
    }
    for i := 0; i < len(nums); i++ {
        if !(*used)[i] {
            if i > 0 && nums[i] == nums[i-1] && !(*used)[i-1] {
                continue // 关键的去重逻辑,跳过重复的数字
            }
            (*used)[i] = true // 标记当前数字已被使用
            p = append(p, nums[i]) // 将当前数字添加到排列中
            generatePermutation47(nums, index+1, p, res, used) // 递归生成下一个位置的排列
            p = p[:len(p)-1] // 回溯,移除当前数字
            (*used)[i] = false // 取消标记当前数字未被使用
        }
    }
    return
}

Pitón

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        def generatePermutation(nums, used, current, result):
            if len(current) == len(nums):
                result.append(current[:])
                return
            
            for i in range(len(nums)):
                if used[i] or (i > 0 and nums[i] == nums[i - 1] and not used[i - 1]):
                    continue
                
                used[i] = True
                current.append(nums[i])
                generatePermutation(nums, used, current, result)
                current.pop()
                used[i] = False
        
        nums.sort() # 对输入数组进行排序,关键的去重逻辑
        result = []
        used = [False] * len(nums)
        generatePermutation(nums, used, [], result)
        return result

Java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        if (nums == null || nums.length == 0) {
            return result;
        }
        
        Arrays.sort(nums); // 对输入数组进行排序,关键的去重逻辑
        boolean[] used = new boolean[nums.length];
        List<Integer> current = new ArrayList<>();
        
        generatePermutation(nums, used, current, result);
        
        return result;
    }
    
    private void generatePermutation(int[] nums, boolean[] used, List<Integer> current, List<List<Integer>> result) {
        if (current.size() == nums.length) {
            result.add(new ArrayList<>(current));
            return;
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {
                continue;
            }
            
            used[i] = true;
            current.add(nums[i]);
            generatePermutation(nums, used, current, result);
            current.remove(current.size() - 1);
            used[i] = false;
        }
    }
}

cpp

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        if (nums.empty()) {
            return result;
        }
        
        sort(nums.begin(), nums.end()); // 对输入数组进行排序,关键的去重逻辑
        vector<bool> used(nums.size(), false);
        vector<int> current;
        
        generatePermutation(nums, used, current, result);
        
        return result;
    }
    
private:
    void generatePermutation(vector<int>& nums, vector<bool>& used, vector<int>& current, vector<vector<int>>& result) {
        if (current.size() == nums.size()) {
            result.push_back(current);
            return;
        }
        
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {
                continue;
            }
            
            used[i] = true;
            current.push_back(nums[i]);
            generatePermutation(nums, used, current, result);
            current.pop_back();
            used[i] = false;
        }
    }
};

Puntos de conocimientos básicos relevantes.

Ir versión:

  • Conocimiento básico:
    • Conceptos básicos del lenguaje Go: familiarícese con conceptos básicos como la sintaxis de Go, estructuras de datos, sectores, bucles y declaraciones condicionales.
    • Sectores y matrices: aprenda la diferencia entre sectores y matrices en Go y cómo usarlos.
    • Recursividad: comprenda el concepto de recursividad y cómo implementar funciones recursivas en Go.

Versión de Python:

  • Conocimiento básico:
    • Conceptos básicos de Python: domine los conocimientos básicos de la sintaxis, tipos de datos, listas, bucles, declaraciones condicionales de Python, etc.
    • Listas y conjuntos: aprenda sobre listas y estructuras de datos de conjuntos en Python, junto con sus operaciones y propiedades.
    • Recursividad: comprenda el concepto de recursividad y cómo implementar funciones recursivas en Python.

Versión de Java:

  • Conocimiento básico:
    • Conceptos básicos de Java: familiarizado con conocimientos básicos de sintaxis de Java, matrices, listas, bucles, declaraciones condicionales, etc.
    • Listas y conjuntos: aprenda sobre las estructuras de datos Lista y Conjunto en Java y cómo usarlas.
    • Recursividad: comprenda el concepto de recursividad y cómo implementar métodos recursivos en Java.

Versión C++:

  • Conocimiento básico:
    • Conceptos básicos de C++: domine conceptos básicos como la sintaxis de C++, matrices, vectores, bucles y declaraciones condicionales.
    • Vector: aprenda sobre la estructura de datos vectoriales en C++ y cómo usarla para almacenar y procesar datos.
    • Recursividad: comprenda el concepto de recursividad y cómo implementar funciones recursivas en C++.

48. Girar imagen

tema

Se le proporciona una matriz 2D de n x n que representa una imagen.

Gire la imagen 90 grados (en el sentido de las agujas del reloj).

Nota:

Tienes que rotar la imagen in situ , lo que significa que tienes que modificar la matriz 2D de entrada directamente. NO asigne otra matriz 2D y realice la rotación.

Ejemplo 1 :

Given input matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

rotate the input matrix in-place such that it becomes:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

Ejemplo 2 :

Given input matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

rotate the input matrix in-place such that it becomes:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

La idea general del tema.

Dada una matriz bidimensional n × n que representa una imagen. Gire la imagen 90 grados en el sentido de las agujas del reloj. Nota: Debe rotar la imagen en su lugar, lo que significa que debe modificar la matriz 2D de entrada directamente. No utilice otra matriz para rotar la imagen.

Ideas para resolver problemas

  • Dada una matriz bidimensional, se requiere girar 90 grados en el sentido de las agujas del reloj.
  • Esta pregunta es relativamente simple, simplemente siga el significado de la pregunta. Aquí se muestran las implementaciones de dos métodos de rotación, rotación en el sentido de las agujas del reloj y rotación en el sentido contrario a las agujas del reloj.
    Al resolver el problema "Rotar imagen", las ideas de resolución de problemas en cada versión son básicamente las mismas, pero la sintaxis y las operaciones del lenguaje específico son ligeramente diferentes. Aquí están las ideas de resolución de problemas para cada versión:

Ir a la versión de ideas para resolver problemas

  1. Transformación diagonal : Primero, realizamos una transformación diagonal, intercambiando los elementos de la matriz a lo largo de la diagonal principal (desde la esquina superior izquierda hasta la esquina inferior derecha). En realidad, este paso gira la matriz hasta la mitad 90 grados en el sentido de las agujas del reloj.

  2. Cambio de simetría del eje vertical : A continuación, realizamos un cambio de simetría del eje vertical para cada fila. Este paso completará la rotación restante de la matriz, haciéndola 90 grados en el sentido de las agujas del reloj.

Ideas para resolver problemas de la versión Python

Las ideas de resolución de problemas de la versión Python son básicamente las mismas que las de la versión Go, incluidos dos pasos de transformación diagonal y cambio de simetría del eje vertical.

Ideas para resolver problemas de la versión Java

Las ideas de resolución de problemas de la versión Java también son similares a las de la versión Go:

  1. Transformación diagonal : Primero, realizamos una transformación diagonal, intercambiando los elementos de la matriz según la diagonal principal.

  2. Inversión de simetría del eje vertical : A continuación, realice un giro de simetría del eje vertical en cada fila para completar la rotación restante de la matriz.

Ideas para resolver problemas de la versión C ++

La idea de solución de la versión C ++ es muy similar a la de la versión Java:

  1. Transformación diagonal : Primero, realizamos una transformación diagonal, intercambiando los elementos de la matriz según la diagonal principal.

  2. Inversión de simetría del eje vertical : luego, realice un cambio de simetría del eje vertical para cada fila para completar la rotación restante de la matriz.

En resumen, cada versión de la idea de resolución de problemas sigue los dos pasos de transformación diagonal y cambio de simetría del eje vertical para lograr una rotación de la matriz de 90 grados en el sentido de las agujas del reloj. Si tiene alguna pregunta sobre una versión específica o necesita una explicación más detallada, hágamelo saber.

código

Ir

// 解法一
func rotate(matrix [][]int) {
    length := len(matrix) // 获取矩阵的长度

    // rotate by diagonal 对角线变换
    for i := 0; i < length; i++ { // 遍历行
        for j := i + 1; j < length; j++ { // 遍历列,从当前行的下一个元素开始
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] // 交换矩阵[i][j]和矩阵[j][i]的值,实现对角线翻转
        }
    }

    // rotate by vertical centerline 竖直轴对称翻转
    for i := 0; i < length; i++ { // 遍历每一行
        for j := 0; j < length/2; j++ { // 遍历每一行的前一半列
            matrix[i][j], matrix[i][length-j-1] = matrix[i][length-j-1], matrix[i][j] // 交换矩阵[i][j]和矩阵[i][length-j-1]的值,实现竖直轴对称翻转
        }
    }
}

Pitón

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        length = len(matrix)

        # rotate by diagonal 对角线变换
        for i in range(length):
            for j in range(i + 1, length):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

        # rotate by vertical centerline 竖直轴对称翻转
        for i in range(length):
            for j in range(length // 2):
                matrix[i][j], matrix[i][length - j - 1] = matrix[i][length - j - 1], matrix[i][j]

Java

class Solution {
    public void rotate(int[][] matrix) {
        int length = matrix.length;

        // rotate by diagonal 对角线变换
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        // rotate by vertical centerline 竖直轴对称翻转
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][length - j - 1];
                matrix[i][length - j - 1] = temp;
            }
        }
    }
}

cpp

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        length = len(matrix)

        # rotate by diagonal 对角线变换
        for i in range(length):
            for j in range(i + 1, length):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

        # rotate by vertical centerline 竖直轴对称翻转
        for i in range(length):
            for j in range(length // 2):
                matrix[i][j], matrix[i][length - j - 1] = matrix[i][length - j - 1], matrix[i][j]

Ir versión

  1. Sector : en Go, un sector es una estructura de datos flexible que se utiliza para manejar matrices dinámicas. En este problema, usamos cortes para representar matrices 2D.

  2. Bucles e iteración : Go utiliza forbucles para iterar sobre matrices y sectores. Aquí, utilizamos forbucles anidados para iterar sobre las filas y columnas de la matriz.

  3. Intercambio de valores de variables : en Go, puede intercambiar los valores de dos variables mediante asignación múltiple. Ésta es la clave para lograr el intercambio de elementos de la matriz.

Versión de Python

  1. Lista : en Python, usamos listas para representar matrices o matrices. La matriz aquí es una lista bidimensional.

  2. Bucles e iteración : Python usa forbucles para iterar sobre listas. En este problema, utilizamos forbucles anidados para iterar sobre las filas y columnas de la matriz.

  3. Asignación múltiple : Python permite el uso de asignaciones múltiples para intercambiar los valores de dos variables, lo cual es útil para intercambiar elementos de matriz.

versión java

  1. Matriz bidimensional : Java utiliza una matriz bidimensional para representar matrices. En este problema, representamos la matriz como int[][]tipo.

  2. Bucles anidados : Java utiliza forbucles anidados para atravesar una matriz bidimensional. El primer bucle se utiliza para iterar sobre las filas y el segundo bucle se utiliza para iterar sobre las columnas.

  3. Variable temporal : utilizamos una variable temporal para almacenar mientras intercambiamos los valores de dos elementos de la matriz.

versión C++

  1. Matriz bidimensional : C++ también utiliza matrices bidimensionales para representar matrices. El tipo de matriz es vector<vector<int>>.

  2. Bucles e iteración : C++ usa forbucles para iterar sobre vectores. Los bucles anidados forse utilizan para iterar sobre vectores bidimensionales.

  3. Variable temporal : al igual que Java, utilizamos una variable temporal para intercambiar los valores de dos elementos de la matriz.

Estos son los conceptos básicos necesarios para resolver este problema, incluidas estructuras de datos y conceptos de programación como bucles, iteraciones y manipulación de variables. Si tiene alguna pregunta específica sobre estas versiones o necesita una explicación más detallada, no dude en preguntar.

49. Anagramas de grupo

tema

Dada una serie de cadenas, agrupe los anagramas.

Ejemplo:

Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

Nota:

  • Todas las entradas estarán en minúsculas.
  • El orden de su salida no importa.

La idea general del tema.

Dada una matriz de cadenas, es necesario agrupar las cadenas con relaciones de anagramas en la matriz de cadenas. La relación de Anagramas significa que los caracteres de las dos cadenas son exactamente iguales pero en diferente orden y están compuestos de permutaciones y combinaciones.

Ideas para resolver problemas

Esta pregunta puede ordenar cada cadena. Una vez completada la clasificación, las cadenas con los mismos anagramas inevitablemente se ordenarán con el mismo resultado. Almacene las cadenas ordenadas como claves en el mapa
. Después de atravesar la matriz, puede obtener un mapa: la clave es la cadena ordenada y el valor corresponde a la cadena de anagramas establecida después de la cadena ordenada.
Finalmente , genere la matriz de cadenas correspondiente a estos valores.
Por supuesto, las siguientes son las ideas de resolución de problemas para cada versión:

Ir a la versión de ideas para resolver problemas

  1. Cree un mapa vacío que agrupe cadenas con la misma composición alfabética.
  2. Cree un sector de resultados vacío.
  3. Defina una función anónima signque acepte una cadena como entrada y devuelva un identificador que represente las letras de la cadena.
  4. Iterar sobre la matriz de cadenas de entrada:
    • Para cada cadena, calcule su identificador alfabético, signimplementado mediante una función anónima.
    • Agregue la cadena actual a un grupo de identificadores correspondientes, organizados mediante asignaciones.
  5. Itere sobre cada grupo en el mapa, convierta el grupo en un segmento y agregue el segmento al segmento resultante.
  6. Devuelve el segmento del resultado final, que contiene cadenas agrupadas alfabéticamente.

Ideas para resolver problemas de la versión Python

  1. Cree un diccionario vacío que agrupe cadenas con la misma composición alfabética.
  2. Iterar sobre la lista de cadenas de entrada:
    • Ordene cada cadena en una tupla que se utilizará como clave de diccionario.
    • Si la clave no existe en el diccionario, se crea una lista vacía como valor y la cadena original se agrega a la lista.
    • Si la clave ya existe en el diccionario, la cadena original se agrega a la lista de claves correspondientes.
  3. Convierte los valores de un diccionario (agrupados) en una lista y devuelve el resultado.

Ideas para resolver problemas de la versión Java

  1. Crea un mapa que agrupe cadenas con la misma composición alfabética. En Java se suele utilizar HashMap.
  2. Iterar sobre la matriz de cadenas de entrada:
    • Convierta cada cadena en una matriz de caracteres y ordene la matriz de caracteres para formar una cadena ordenada.
    • Utilice la cadena ordenada como clave del mapa y la cadena original como valor que se almacenará en el mapa.
  3. Convierte las agrupaciones del mapa en una lista y devuelve el resultado.

Ideas para resolver problemas de la versión C ++

  1. Cree un mapa (unordered_map) que agrupe cadenas con la misma composición alfabética.
  2. Iterar sobre el vector de cadena de entrada:
    • Ordene cada cadena para formar una cadena ordenada.
    • Utilice la cadena ordenada como clave del mapa y la cadena original como valor que se almacenará en el mapa.
  3. Convierte valores asignados (grupos) en vectores y devuelve el resultado.

Independientemente de la versión de la solución que utilice, la idea básica es utilizar una estructura de datos (como un mapa o un diccionario) para organizar y almacenar cadenas con la misma composición alfabética y luego agruparlas. Las cadenas se ordenan para garantizar que
las cadenas de los mismos anagramas tengan el mismo identificador para que se agrupen correctamente.

código

Ir

func groupAnagrams(strs []string) [][]string {
    // 创建一个空的映射(map),用于将具有相同字母组成的字符串分组
    hashMap := map[string][]string{}
    // 创建一个空的结果切片(slice)
    res := [][]string{}

    // 定义一个匿名函数 sign,该函数接受一个字符串 s,并返回一个表示 s 字母组成的标识符
    sign := func(s string) string {
        // 创建一个长度为 26 的字节数组,用于统计每个字母出现的次数
        strB := [26]byte{}
        // 遍历字符串 s 中的每个字符
        for _, v := range s {
            // 将字符 v 转换为小写字母,并将对应字母的计数加一
            strB[v-'a']++
        }
        // 将字节数组转换为字符串并返回
        return string(strB[:])
    }

    // 遍历输入的字符串切片 strs
    for _, v := range strs {
        // 对当前字符串 v 计算其字母组成的标识符
        signV := sign(v)
        // 将当前字符串添加到对应标识符的分组中
        hashMap[signV] = append(hashMap[signV], v)
    }

    // 遍历映射中的每个分组,并将其添加到结果切片 res 中
    for _, v := range hashMap {
        res = append(res, v)
    }
    // 返回最终的结果切片,其中包含了按字母组成分组的字符串
    return res
}

Pitón

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # 创建一个字典,用于将具有相同字母组成的字符串分组
        hashMap = {}

        # 遍历输入的字符串列表
        for str in strs:
            # 将字符串转换为排序后的元组,作为字典的键
            sorted_str = tuple(sorted(str))
            # 将原始字符串添加到对应键的列表中
            hashMap.setdefault(sorted_str, []).append(str)

        # 将字典的值(分组)转换为列表,并返回结果
        result = list(hashMap.values())
        return result

Java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        // 创建一个映射,用于将具有相同字母组成的字符串分组
        Map<String, List<String>> hashMap = new HashMap<>();

        // 遍历输入的字符串数组
        for (String str : strs) {
            // 将字符串转换为字符数组,并排序
            char[] charArray = str.toCharArray();
            Arrays.sort(charArray);
            // 排序后的字符数组作为键,原始字符串作为值存入映射中
            String sortedStr = new String(charArray);
            if (!hashMap.containsKey(sortedStr)) {
                hashMap.put(sortedStr, new ArrayList<>());
            }
            hashMap.get(sortedStr).add(str);
        }

        // 将映射中的分组转换为列表
        List<List<String>> result = new ArrayList<>(hashMap.values());
        return result;
    }
}

cpp

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // 创建一个映射,用于将具有相同字母组成的字符串分组
        unordered_map<string, vector<string>> hashMap;
        
        // 遍历输入的字符串向量
        for (string str : strs) {
            // 将字符串排序,作为映射的键
            string sortedStr = str;
            sort(sortedStr.begin(), sortedStr.end());
            // 将原始字符串添加到对应键的向量中
            hashMap[sortedStr].push_back(str);
        }
        
        // 将映射的值(分组)转换为向量,并返回结果
        vector<vector<string>> result;
        for (auto& pair : hashMap) {
            result.push_back(pair.second);
        }
        return result;
    }
};

Conceptos básicos requeridos para cada versión:

Ir versión

  • Conceptos básicos del lenguaje Go : comprenda la sintaxis básica del lenguaje Go, incluida la declaración de variables, la definición de funciones, las declaraciones condicionales, los bucles, etc.
  • Sectores y mapas : aprenda a utilizar sectores y mapas para trabajar con datos de recopilación. En esta solución, se utilizan cortes y mapeos para organizar y almacenar
    anagramas agrupados.
  • Funciones anónimas : aprenda a definir funciones anónimas, como las de las soluciones sign.
  • Operaciones de caracteres : aprenda a manipular cadenas, incluido el recorrido y la comparación de caracteres.

Versión de Python

  • Conceptos básicos de Python : familiarícese con la sintaxis básica de Python, incluidas variables, listas, bucles, declaraciones condicionales, etc.
  • Diccionarios y listas : aprenda a utilizar diccionarios y listas para trabajar con datos de recopilación. En esta solución, se utiliza un diccionario para organizar y almacenar
    anagramas agrupados.
  • Operaciones de cadenas : familiarizado con las operaciones básicas de las cadenas de Python, incluida la clasificación de cadenas.
  • Tuplas : aprenda a utilizar tuplas, como tuplas de cadenas ordenadas en soluciones.

versión java

  • Conceptos básicos de Java : comprenda la sintaxis básica de Java, incluidas definiciones de clases y métodos, bucles, declaraciones condicionales, etc.
  • Marco de colecciones : obtenga información sobre el marco de colecciones de Java, incluido el uso de HashMapy ArrayList
    . En esta solución, utilícela HashMappara organizar y almacenar anagramas agrupados.
  • Manipulación y clasificación de caracteres : familiarícese con la manipulación de caracteres en Java, incluida la conversión de cadenas en matrices de caracteres y su clasificación.

versión C++

  • Conceptos básicos de C++ : comprenda la sintaxis básica de C++, incluida la declaración de variables, la definición de funciones, los bucles, las declaraciones condicionales, etc.
  • STL (Biblioteca de plantillas estándar) : familiarizado con C++ STL, incluido el uso de unordered_mapy vector
    . En esta solución, utilícela unordered_mappara organizar y almacenar anagramas agrupados.
  • Manipulación y clasificación de caracteres : aprenda a manipular cadenas en C++, incluida su clasificación.

Independientemente de la versión de idioma que elija, se requieren conocimientos básicos de programación, incluido el dominio de la sintaxis básica y las operaciones de estructura de datos, para comprender y modificar estas soluciones. Además, comprender la idea básica del algoritmo también será útil para comprender estos códigos.

Supongo que te gusta

Origin blog.csdn.net/qq_42531954/article/details/133247558
Recomendado
Clasificación