Método de alta descomposición Go-Python-Java-C-LeetCode-Colección de la sexta 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
Insertar descripción de la imagen aquí

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 resolución Python-Java-C-LeetCode: colección de la cuarta semana
Método de alta resolución Go-Python-Java-C-LeetCode: colección de la quinta semana
Parte del contenido de este artículo proviene de la colección en línea y la 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.

36. Sudoku válido

tema

Determina si un tablero de Sudoku de 9x9 es válido. Sólo es necesario validar las celdas completadas de acuerdo con las siguientes reglas :

  1. Cada fila debe contener los dígitos 1-9sin repetición.
  2. Cada columna debe contener los dígitos 1-9sin repetición.
  3. Cada uno de los 9 3x3subcuadros de la grilla debe contener los dígitos 1-9sin repetición.

La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente.

Un sudoku parcialmente lleno que es válido.

El tablero de Sudoku podría llenarse parcialmente, donde las celdas vacías se llenan con el personaje '.'.

Ejemplo 1:

Input:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: true

Ejemplo 2:

Input:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being 
    modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.

Nota:

  • Un tablero de Sudoku (parcialmente lleno) podría ser válido pero no necesariamente tiene solución.
  • Sólo es necesario validar las celdas completadas de acuerdo con las reglas mencionadas.
  • El tablero dado contiene solo dígitos 1-9y el carácter '.'.
  • El tamaño del tablero dado es siempre 9x9.

La idea general del tema.

Determina si un Sudoku de 9x9 es válido. Simplemente siga las siguientes reglas para verificar si los números que ha ingresado son válidos.

  1. Los números del 1 al 9 sólo pueden aparecer una vez en cada línea.
  2. Los números del 1 al 9 solo pueden aparecer una vez en cada columna.
  3. Los números del 1 al 9 solo pueden aparecer una vez en cada casa de 3x3 separadas por una línea gruesa y continua.

Ideas para resolver problemas

La siguiente es una introducción detallada a las ideas de resolución de problemas para cada versión:

Ir a la versión de ideas para resolver problemas

  1. Cree tres matrices booleanas bidimensionales: rowbuf, colbuf, boxbuf, que se utilizan para almacenar en caché si han aparecido los números en cada fila, cada columna y cada cuadro de 3x3.

  2. Atraviesa el tablero de Sudoku y revisa cada cuadrado:

    • Si la cuadrícula contiene caracteres '.', se omitirá y no se procesará.
    • Si la cuadrícula contiene caracteres numéricos, conviértala a un número entero y verifique si ya aparece en la fila, columna o cuadro de 3x3 actual.
    • Si ya apareció, devuelve false, indicando que el Sudoku no es válido.
    • De lo contrario, la matriz de caché se actualizará para marcar que ha aparecido el número.
  3. Si pasa la verificación anterior, devuelve true, indicando que el Sudoku es válido.

Ideas para resolver problemas de la versión Python

  1. Cree tres matrices booleanas bidimensionales: row_used, col_used, cell_used, para registrar la aparición de números en cada fila, cada columna y cada celda de 3x3.

  2. Atraviesa el tablero de Sudoku y revisa cada cuadrado:

    • Si la cuadrícula contiene caracteres '.', se omitirá y no se procesará.
    • Si la cuadrícula contiene caracteres numéricos, conviértalos a números enteros y verifique si ya aparecen en la fila, columna o celda de 3x3 actual.
    • Si ya apareció, devuelve false, indicando que el Sudoku no es válido.
    • De lo contrario, marca que el número ocurrió en la fila, columna y celda actual.
  3. Si pasa la verificación anterior, devuelve true, indicando que el Sudoku es válido.

ideas para resolver problemas de la versión ava

  1. Cree tres matrices booleanas bidimensionales: rowbuf, colbuf, boxbuf, que se utilizan para almacenar en caché si han aparecido los números en cada fila, cada columna y cada cuadro de 3x3.

  2. Atraviesa el tablero de Sudoku y revisa cada cuadrado:

    • Si la cuadrícula contiene caracteres '.', se omitirá y no se procesará.
    • Si la cuadrícula contiene caracteres numéricos, conviértalos a números enteros y verifique si ya aparecen en la fila, columna o cuadro de 3x3 actual.
    • Si ya apareció, devuelve false, indicando que el Sudoku no es válido.
    • De lo contrario, la matriz de caché se actualizará para marcar que ha aparecido el número.
  3. Si pasa la verificación anterior, devuelve true, indicando que el Sudoku es válido.

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

  1. Cree tres matrices de enteros bidimensionales: row, column, box, para realizar un seguimiento de la aparición de números en cada fila, cada columna y cada cuadro de 3x3.

  2. Atraviesa el tablero de Sudoku y revisa cada cuadrado:

    • Si la cuadrícula contiene caracteres '.', se omitirá y no se procesará.
    • Si la cuadrícula contiene caracteres numéricos, conviértala a un número entero y verifique si ya aparece en la fila, columna o cuadro de 3x3 actual.
    • Si ya apareció, devuelve false, indicando que el Sudoku no es válido.
    • En caso contrario, se actualizará el contador correspondiente para marcar que se ha producido el número.
  3. Si pasa la verificación anterior, devuelve true, indicando que el Sudoku es válido.

código

Ir

func isValidSudoku1(board [][]byte) bool {
    // 创建三个二维布尔数组,用于缓存每行、每列和每个3x3的方框中数字是否已经出现
    rowbuf, colbuf, boxbuf := make([][]bool, 9), make([][]bool, 9), make([][]bool, 9)
    for i := 0; i < 9; i++ {
        rowbuf[i] = make([]bool, 9)
        colbuf[i] = make([]bool, 9)
        boxbuf[i] = make([]bool, 9)
    }

    // 遍历一次,添加缓存
    for r := 0; r < 9; r++ {
        for c := 0; c < 9; c++ {
            if board[r][c] != '.' {
                // 将字符数字转换为整数
                num := board[r][c] - '0' - byte(1)
                
                // 检查行、列和3x3方格中是否已经出现相同的数字
                if rowbuf[r][num] || colbuf[c][num] || boxbuf[r/3*3+c/3][num] {
                    return false
                }
                
                // 更新缓存数组,标记数字已经出现
                rowbuf[r][num] = true
                colbuf[c][num] = true
                boxbuf[r/3*3+c/3][num] = true // r,c 转换到box方格中
            }
        }
    }
    
    // 如果通过上述检查,则数独有效
    return true
}

Pitón

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        row_used = [[False] * 9 for _ in range(9)]      # 记录每一行出现过的数字
        col_used = [[False] * 9 for _ in range(9)]      # 记录每一列出现过的数字
        cell_used = [[False] * 9 for _ in range(9)]     # 记录每一个单元格出现过的数字
        
        for r in range(9):
            for c in range(9):
                if board[r][c] == '.': continue     # 不为数字的位置跳过处理
                char_id = int(board[r][c]) - 1      # 获取数字对应的编号(索引)
                
                # 检查当前数字是否已经在当前行、当前列或当前单元格中出现过
                if row_used[r][char_id] or col_used[c][char_id] or cell_used[r // 3 * 3 + c // 3][char_id]:
                    return False    # 如果出现重复,则数独无效
                
                # 否则标记该数字出现过
                row_used[r][char_id], col_used[c][char_id], cell_used[r // 3 * 3 + c // 3][char_id] = True, True, True  

        return True  # 如果通过了所有检查,数独是有效的

Java

class Solution {
    public boolean isValidSudoku(char[][] board) {
        boolean[][] rowbuf = new boolean[9][9];
        boolean[][] colbuf = new boolean[9][9];
        boolean[][] boxbuf = new boolean[9][9];

        // 遍历一次,添加缓存
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                if (board[r][c] != '.') {
                    int num = board[r][c] - '1';
                    // 检查行
                    if (rowbuf[r][num]) {
                        return false;
                    }
                    rowbuf[r][num] = true;

                    // 检查列
                    if (colbuf[c][num]) {
                        return false;
                    }
                    colbuf[c][num] = true;

                    // 检查3x3的方框
                    int boxIndex = (r / 3) * 3 + c / 3;
                    if (boxbuf[boxIndex][num]) {
                        return false;
                    }
                    boxbuf[boxIndex][num] = true;
                }
            }
        }

        return true;
    }
}

cpp

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int row[9][9] = {0}; // 用于跟踪每一行中数字的出现次数
        int column[9][9] = {0}; // 用于跟踪每一列中数字的出现次数
        int box[9][9] = {0}; // 用于跟踪每个3x3方框中数字的出现次数

        // 遍历数独棋盘
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                int box_index = i / 3 * 3 + j / 3; // 计算当前单元格属于哪个3x3方框
                int temp = board[i][j] - '0' - 1; // 将字符数字转换为整数,范围是0到8
                if (temp == -1) continue; // 如果是'.',跳过当前单元格

                // 检查当前数字是否已经在当前行、当前列或当前方框中出现过
                if (row[i][temp] == 1 || column[j][temp] == 1 || box[box_index][temp] == 1) {
                    return false; // 如果出现重复,则数独无效
                }

                // 更新相应的计数器
                ++row[i][temp];
                ++column[j][temp];
                ++box[box_index][temp];
            }
        }

        return true; // 如果通过了所有检查,数独是有效的
    }
};

Cuando se trata de soluciones en diferentes versiones de lenguajes de programación, es necesario conocer algunos conceptos y sintaxis básicos para comprender cómo funciona el código. Estos son los conceptos básicos detallados para cada versión:

Ir versión

  • Matrices y cortes : las matrices en Go tienen una longitud fija, mientras que los cortes tienen una longitud variable. En esta solución, los sectores se utilizan para almacenar apariciones de números en filas, columnas y cuadros.

  • Arreglos bidimensionales : Go admite arreglos multidimensionales, por lo que puede crear fácilmente arreglos bidimensionales para representar el tablero de Sudoku y las ocurrencias numéricas.

  • Bucles : use forun bucle para recorrer todos los elementos en una matriz bidimensional, lo cual es muy útil al resolver problemas de Sudoku.

  • Declaraciones condicionales : utilice ifdeclaraciones condicionales para verificar si el número ha aparecido y realice el procesamiento correspondiente de acuerdo con las condiciones.

  • Conversión de tipo : la conversión de tipo de carácter a entero se utiliza en el código para convertir números de caracteres en números enteros para la indexación.

Versión de Python

  • Lista : La lista en Python es una secuencia mutable que se utiliza para almacenar el tablero de Sudoku y las apariciones de números.

  • Listas bidimensionales : las listas anidadas facilitan la representación de estructuras de datos bidimensionales, como tableros de Sudoku y ocurrencias numéricas.

  • Bucles : utilice forun bucle para iterar sobre todos los elementos de una lista bidimensional, lo cual es muy útil a la hora de resolver problemas de Sudoku.

  • Declaraciones condicionales : utilice ifdeclaraciones condicionales para verificar si el número ha aparecido y realice el procesamiento correspondiente de acuerdo con las condiciones.

  • Conversión de tipo : la conversión de tipo de carácter a entero se utiliza en el código para convertir números de caracteres en números enteros para la indexación.

  • Programación orientada a objetos : la solución utiliza un estilo de programación orientada a objetos, que encapsula la lógica de verificar la validez del Sudoku en una clase.

versión ava

  • Matriz : Las matrices en Java tienen una longitud fija y se pueden usar para almacenar tableros de Sudoku y ocurrencias numéricas.

  • Matriz bidimensional : utilice una matriz bidimensional para representar el tablero de Sudoku y las apariciones de números.

  • Bucles : use forun bucle para recorrer todos los elementos en una matriz bidimensional, lo cual es muy útil al resolver problemas de Sudoku.

  • Declaraciones condicionales : utilice ifdeclaraciones condicionales para verificar si el número ha aparecido y realice el procesamiento correspondiente de acuerdo con las condiciones.

  • Conversión de tipo : la conversión de tipo de carácter a entero se utiliza en el código para convertir números de caracteres en números enteros para la indexación.

versión C++

  • Matriz : Las matrices en C++ tienen una longitud fija y se pueden usar para almacenar tableros de Sudoku y ocurrencias de números.

  • Matriz bidimensional : utilice una matriz bidimensional para representar el tablero de Sudoku y las apariciones de números.

  • Bucles : use forun bucle para recorrer todos los elementos en una matriz bidimensional, lo cual es muy útil al resolver problemas de Sudoku.

  • Declaraciones condicionales : utilice ifdeclaraciones condicionales para verificar si el número ha aparecido y realice el procesamiento correspondiente de acuerdo con las condiciones.

  • Conversión de tipo : la conversión de tipo de carácter a entero se utiliza en el código para convertir números de caracteres en números enteros para la indexación.

Comprender estos puntos de conocimiento básicos puede ayudarlo a comprender cómo cada versión del código implementa la verificación del Sudoku. Además, es necesario comprender los conceptos básicos de matrices y bucles para comprender mejor cómo funciona el código.

37. Solucionador de sudokus

tema

Escribe un programa para resolver un Sudoku llenando las celdas vacías.

Una solución de sudoku debe cumplir todas las reglas siguientes :

  1. Cada uno de los dígitos 1-9debe aparecer exactamente una vez en cada fila.
  2. Cada uno de los dígitos 1-9debe aparecer exactamente una vez en cada columna.
  3. Cada uno de los dígitos 1-9debe aparecer exactamente una vez en cada uno de los 9 3x3subcuadros de la cuadrícula.

Las celdas vacías están indicadas por el carácter '.'.

Un sudoku...

…y sus números de solución marcados en rojo.

Nota:

  • El tablero dado contiene solo dígitos 1-9y el carácter '.'.
  • Puede suponer que el Sudoku dado tendrá una única solución.
  • El tamaño del tablero dado es siempre 9x9.

La idea general del tema.

Escribe un programa para resolver un problema de Sudoku usando espacios llenos. La solución de un Sudoku debe seguir las siguientes reglas:

  1. Los números del 1 al 9 sólo pueden aparecer una vez en cada línea.
  2. Los números del 1 al 9 solo pueden aparecer una vez en cada columna.
  3. Los números del 1 al 9 solo pueden aparecer una vez en cada casa de 3x3 separadas por una línea gruesa y continua.

Los espacios en blanco están representados por '.'.

Ideas para resolver problemas

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

  1. Definir estructuras y estructuras de datos : Primero, defina una estructura positionpara representar las posiciones (filas y columnas) en el Sudoku. Cree un segmento vacío positionpara almacenar la información de ubicación del número que se va a completar. También necesita definir una variable booleana findpara indicar si se encuentra una solución.

  2. Recorrer la cuadrícula de Sudoku : recorra cada cuadrícula de Sudoku. Si la cuadrícula actual es '.', significa que es necesario completar los números y agregar la información de su posición al positionsegmento.

  3. Enumeración de seguimiento de fuerza bruta DFS : utilice la búsqueda en profundidad (DFS) para la enumeración de seguimiento de fuerza bruta. En cada posición en blanco, intente completar los números del 1 al 9 y luego verifique si se siguen las reglas del Sudoku. Si se cumplen las reglas, continúe ocupando de forma recursiva el siguiente puesto. Si se encuentra una solución, findconfigúrelo truey regrese.

  4. Verifique las reglas del Sudoku : al completar los números en cada posición, debe verificar si se cumplen las siguientes tres reglas:

    • ¿Hay números repetidos en las filas horizontales?
    • ¿Hay números repetidos en las filas verticales?
    • ¿Hay números repetidos en la cuadrícula de Jiugong?
  5. Retroceder y restablecer : si no se encuentra ninguna solución después de completar el número en la posición actual, debe restablecer la posición a '.' y continuar intentando con el siguiente número.

  6. Solución completa : cuando se encuentra un conjunto de soluciones, configúrelo findy trueregrese. No es necesario seguir retrocediendo en este punto.

Ideas para resolver problemas de la versión Python:

Las ideas de resolución de problemas de la versión Python son similares a las de la versión Go. La principal diferencia radica en la sintaxis y la representación de la estructura de datos. Las ideas específicas para la resolución de problemas son las siguientes:

  1. Defina clases y métodos : utilice clases y métodos de Python para organizar su código. Definir una clase Solutionpara resolver problemas de Sudoku.

  2. Solución recursiva : Solución recursiva que utiliza búsqueda en profundidad (DFS). Método Create dfs, donde la lógica principal es similar a la versión Go.

  3. Operaciones de bits : utilice operaciones de bits para comprobar la validez de los números, como AND bit a bit, OR bit a bit, XOR bit a bit, etc.

  4. Lista (Lista) : Python usa una lista (Lista) para almacenar la información de posición de los números que se completarán y para emitir juicios.

  5. Retroceder y restablecer : cuando no se encuentra ninguna solución después de completar los números en la posición actual, debe restablecer la posición a '.' y continuar intentando con el siguiente número.

Ideas para resolver problemas de la versión Java:

Las ideas de resolución de problemas de la versión Java son similares a las de la versión Python, la principal diferencia radica en la representación de la sintaxis y la estructura de datos. Las ideas específicas para la resolución de problemas son las siguientes:

  1. Definir clases y métodos : Java es un lenguaje de programación orientado a objetos, por lo que utiliza clases y métodos para organizar el código. Definir una clase Solutionpara resolver problemas de Sudoku.

  2. Solución recursiva : Solución recursiva que utiliza búsqueda en profundidad (DFS). Método de creación dfs, donde la lógica principal es similar a la versión de Python.

  3. Operaciones de bits : utilice operaciones de bits para comprobar la validez de los números, como AND bit a bit, OR bit a bit, XOR bit a bit, etc.

  4. Lista (Lista) : La lista se utiliza en Java para almacenar la información de posición de los números a completar y emitir juicios.

  5. Retroceder y restablecer : cuando no se encuentra ninguna solución después de completar los números en la posición actual, debe restablecer la posición a '.' y continuar intentando con el siguiente número.

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

Las ideas de resolución de problemas de la versión C++ son similares a las de las versiones Go, Python y Java, la principal diferencia radica en la sintaxis y la representación de la estructura de datos. Las ideas específicas para la resolución de problemas son las siguientes:

  1. Definir clases y funciones : C++ usa clases y funciones para organizar el código. Definir una clase Solutionpara resolver problemas de Sudoku.

  2. Solución recursiva : Solución recursiva que utiliza búsqueda en profundidad (DFS). Cree dfsun método donde la lógica principal sea similar a otras versiones.

  3. Operaciones de bits : utilice operaciones de bits para comprobar la validez de los números, como AND bit a bit, OR bit a bit, XOR bit a bit, etc.

  4. Vector (Vector) : Vector (Vector) se utiliza en C ++ para almacenar la información de posición del número a completar y hacer juicios.

  5. Retroceder y restablecer : cuando no se encuentra ninguna solución después de completar los números en la posición actual, debe restablecer la posición a '.' y continuar intentando con el siguiente número.

En general, no importa qué lenguaje de programación se utilice, la idea básica para resolver problemas de Sudoku es utilizar la búsqueda en profundidad (DFS) para realizar una enumeración de retroceso, mientras se utilizan operaciones de bits y estructuras de datos adecuadas para verificar y registrar la legalidad de los números. Estas ideas son comunes en diferentes lenguajes de programación y solo deben implementarse en consecuencia de acuerdo con las características del lenguaje.

código

Ir

// 定义一个结构体 position,表示数独中的位置(行和列)
type position struct {
    x int // 行
    y int // 列
}

// 主函数,用于解数独
func solveSudoku(board [][]byte) {
    // 创建一个空的 position 切片,用于存储待填入数字的位置信息
    pos, find := []position{}, false

    // 遍历数独的每个格子
    for i := 0; i < len(board); i++ {
        for j := 0; j < len(board[0]); j++ {
            // 如果当前格子是'.',表示需要填入数字,将其位置信息加入 pos 切片
            if board[i][j] == '.' {
                pos = append(pos, position{x: i, y: j})
            }
        }
    }

    // 调用 putSudoku 函数来填充数独
    putSudoku(&board, pos, 0, &find)
}

// 递归函数,用于填充数独
func putSudoku(board *[][]byte, pos []position, index int, succ *bool) {
    // 如果已经成功找到解决方案,则返回
    if *succ == true {
        return
    }
    // 如果已经遍历完了所有待填入的位置,则表示找到了解决方案
    if index == len(pos) {
        *succ = true
        return
    }
    // 尝试填入数字 1 到 9
    for i := 1; i < 10; i++ {
        // 检查当前位置是否可以填入数字 i,同时确保还没有找到解决方案
        if checkSudoku(board, pos[index], i) && !*succ {
            // 填入数字 i
            (*board)[pos[index].x][pos[index].y] = byte(i) + '0'
            // 递归调用 putSudoku 函数,继续填充下一个位置
            putSudoku(board, pos, index+1, succ)
            // 如果已经找到解决方案,返回
            if *succ == true {
                return
            }
            // 如果在当前位置填入数字 i 后没有找到解决方案,则将其重置为'.',继续尝试下一个数字
            (*board)[pos[index].x][pos[index].y] = '.'
        }
    }
}

// 检查当前位置是否可以填入指定的数字
func checkSudoku(board *[][]byte, pos position, val int) bool {
    // 判断横行是否有重复数字
    for i := 0; i < len((*board)[0]); i++ {
        if (*board)[pos.x][i] != '.' && int((*board)[pos.x][i]-'0') == val {
            return false
        }
    }
    // 判断竖行是否有重复数字
    for i := 0; i < len((*board)); i++ {
        if (*board)[i][pos.y] != '.' && int((*board)[i][pos.y]-'0') == val {
            return false
        }
    }
    // 判断九宫格是否有重复数字
    posx, posy := pos.x-pos.x%3, pos.y-pos.y%3
    for i := posx; i < posx+3; i++ {
        for j := posy; j < posy+3; j++ {
            if (*board)[i][j] != '.' && int((*board)[i][j]-'0') == val {
                return false
            }
        }
    }
    // 如果以上条件都不满足,说明可以填入该数字
    return true
}

Pitón

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        # 定义翻转位的函数,用于更新行、列和块的状态
        def flip(i: int, j: int, digit: int):
            line[i] ^= (1 << digit)
            column[j] ^= (1 << digit)
            block[i // 3][j // 3] ^= (1 << digit)

        # 深度优先搜索函数
        def dfs(pos: int):
            nonlocal valid
            if pos == len(spaces):  # 如果所有空格都填满了,找到了解
                valid = True
                return

            i, j = spaces[pos]  # 获取当前空格的坐标
            # 计算当前可以填入的数字的掩码
            mask = ~(line[i] | column[j] | block[i // 3][j // 3]) & 0x1ff
            while mask:
                digitMask = mask & (-mask)  # 获取最低位的1
                digit = bin(digitMask).count("0") - 1  # 计算数字
                flip(i, j, digit)  # 更新状态
                board[i][j] = str(digit + 1)  # 填入数字
                dfs(pos + 1)  # 递归下一个空格
                flip(i, j, digit)  # 恢复状态
                mask &= (mask - 1)  # 去掉最低位的1
                if valid:
                    return

        line = [0] * 9  # 记录每一行的数字状态
        column = [0] * 9  # 记录每一列的数字状态
        block = [[0] * 3 for _ in range(3)]  # 记录每个块的数字状态
        valid = False  # 记录是否找到解
        spaces = list()  # 记录所有空格的坐标

        # 遍历数独,初始化状态
        for i in range(9):
            for j in range(9):
                if board[i][j] != ".":
                    digit = int(board[i][j]) - 1
                    flip(i, j, digit)

        # 不断尝试填充数字,直到不能再填充为止
        while True:
            modified = False
            for i in range(9):
                for j in range(9):
                    if board[i][j] == ".":
                        mask = ~(line[i] | column[j] | block[i // 3][j // 3]) & 0x1ff
                        if not (mask & (mask - 1)):  # 如果mask中只有一个1,即只有一种可能的数字
                            digit = bin(mask).count("0") - 1
                            flip(i, j, digit)
                            board[i][j] = str(digit + 1)
                            modified = True
            if not modified:
                break  # 如果没有发生改变,说明无法再填充了

        # 找到所有空格的坐标
        for i in range(9):
            for j in range(9):
                if board[i][j] == ".":
                    spaces.append((i, j))

        dfs(0)  # 开始深度优先搜索,填充剩余的空格

Java

class Solution {
    private int[] line = new int[9];  // 记录每一行的数字状态
    private int[] column = new int[9];  // 记录每一列的数字状态
    private int[][] block = new int[3][3];  // 记录每个块的数字状态
    private boolean valid = false;  // 记录是否找到解
    private List<int[]> spaces = new ArrayList<int[]>();  // 记录所有空格的坐标

    public void solveSudoku(char[][] board) {
        // 初始化行、列和块的状态
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] != '.') {
                    int digit = board[i][j] - '0' - 1;
                    flip(i, j, digit);
                }
            }
        }

        // 不断尝试填充数字,直到不能再填充为止
        while (true) {
            boolean modified = false;
            for (int i = 0; i < 9; ++i) {
                for (int j = 0; j < 9; ++j) {
                    if (board[i][j] == '.') {
                        int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff;
                        if ((mask & (mask - 1)) == 0) {  // 如果mask中只有一个1,即只有一种可能的数字
                            int digit = Integer.bitCount(mask - 1);
                            flip(i, j, digit);
                            board[i][j] = (char) (digit + '0' + 1);
                            modified = true;
                        }
                    }
                }
            }
            if (!modified) {
                break;  // 如果没有发生改变,说明无法再填充了
            }
        }

        // 找到所有空格的坐标
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') {
                    spaces.add(new int[]{i, j});
                }
            }
        }

        dfs(board, 0);  // 开始深度优先搜索,填充剩余的空格
    }

    public void dfs(char[][] board, int pos) {
        if (pos == spaces.size()) {  // 如果所有空格都填满了,找到了解
            valid = true;
            return;
        }

        int[] space = spaces.get(pos);
        int i = space[0], j = space[1];
        int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff;
        for (; mask != 0 && !valid; mask &= (mask - 1)) {
            int digitMask = mask & (-mask);
            int digit = Integer.bitCount(digitMask - 1);
            flip(i, j, digit);
            board[i][j] = (char) (digit + '0' + 1);
            dfs(board, pos + 1);
            flip(i, j, digit);
        }
    }

    public void flip(int i, int j, int digit) {
        line[i] ^= (1 << digit);
        column[j] ^= (1 << digit);
        block[i / 3][j / 3] ^= (1 << digit);
    }
}

cpp

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        vector<int> line(9, 0);  // 记录每一行的数字状态
        vector<int> column(9, 0);  // 记录每一列的数字状态
        vector<vector<int>> block(3, vector<int>(3, 0));  // 记录每个块的数字状态
        bool valid = false;  // 记录是否找到解
        vector<pair<int, int>> spaces;  // 记录所有空格的坐标

        // 初始化行、列和块的状态
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] != '.') {
                    int digit = board[i][j] - '0' - 1;
                    flip(line, column, block, i, j, digit);
                }
            }
        }

        // 不断尝试填充数字,直到不能再填充为止
        while (true) {
            bool modified = false;
            for (int i = 0; i < 9; ++i) {
                for (int j = 0; j < 9; ++j) {
                    if (board[i][j] == '.') {
                        int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff;
                        if ((mask & (mask - 1)) == 0) {  // 如果mask中只有一个1,即只有一种可能的数字
                            int digit = __builtin_popcount(mask - 1);
                            flip(line, column, block, i, j, digit);
                            board[i][j] = digit + '0' + 1;
                            modified = true;
                        }
                    }
                }
            }
            if (!modified) {
                break;  // 如果没有发生改变,说明无法再填充了
            }
        }

        // 找到所有空格的坐标
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') {
                    spaces.push_back({i, j});
                }
            }
        }

        dfs(board, line, column, block, spaces, 0, valid);  // 开始深度优先搜索,填充剩余的空格
    }

    void dfs(vector<vector<char>>& board, vector<int>& line, vector<int>& column, vector<vector<int>>& block, vector<pair<int, int>>& spaces, int pos, bool& valid) {
        if (pos == spaces.size()) {  // 如果所有空格都填满了,找到了解
            valid = true;
            return;
        }

        pair<int, int> space = spaces[pos];
        int i = space.first, j = space.second;
        int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff;
        for (; mask != 0 && !valid; mask &= (mask - 1)) {
            int digitMask = mask & -mask;
            int digit = __builtin_ctz(digitMask);
            flip(line, column, block, i, j, digit);
            board[i][j] = digit + '0' + 1;
            dfs(board, line, column, block, spaces, pos + 1, valid);
            flip(line, column, block, i, j, digit);
        }
    }

    void flip(vector<int>& line, vector<int>& column, vector<vector<int>>& block, int i, int j, int digit) {
        line[i] ^= (1 << digit);
        column[j] ^= (1 << digit);
        block[i / 3][j / 3] ^= (1 << digit);
    }
};

Estos son los puntos clave de conocimiento para las versiones Go, Python, Java y C++:

Ir versión:

  1. Estructura : En Go, verás el uso de estructuras para representar información de posición en Sudoku, como filas y columnas.

  2. Recursividad : el algoritmo principal para resolver problemas de Sudoku es la recursividad de búsqueda en profundidad (DFS). Debe comprender el concepto de recursividad y cómo implementar funciones recursivas en Go.

  3. Sector : utilizará sectores para almacenar la información de posición de los números que se completarán y para emitir juicios.

  4. Operaciones de bits : las operaciones de bits son la clave para determinar si un número es legal. Debe comprender las operaciones bit a bit en Go, como bit a bit AND, bit a bit OR, bit a bit XOR, etc., y cómo usarlas para verificar la validez de los números.

Versión de Python:

  1. Clases y métodos : Python usa clases y métodos para organizar el código. Debe comprender cómo definir clases, métodos y cómo realizar operaciones de datos en clases.

  2. Recursividad : la versión de Python también utiliza la recursividad de búsqueda en profundidad (DFS) para resolver problemas de Sudoku. Es necesario comprender el concepto de recursividad y cómo implementar funciones recursivas en Python.

  3. Operaciones de bits : las operaciones de bits también son clave en Python y se utilizan para comprobar la validez de los números. Debe comprender las operaciones bit a bit en Python, como bit a bit AND, bit a bit OR, bit a bit XOR, etc.

  4. Lista : las listas en Python se utilizan para almacenar la información de posición de los números que se van a completar y para emitir juicios.

Versión de Java:

  1. Clases y métodos : Java es un lenguaje de programación orientado a objetos y necesita saber cómo definir clases, métodos y cómo realizar operaciones de datos en clases.

  2. Recursividad : la versión de Java también utiliza la recursividad de búsqueda en profundidad (DFS) para resolver problemas de Sudoku. Es necesario comprender el concepto de recursividad y cómo implementar funciones recursivas en Java.

  3. Operaciones de bits : las operaciones de bits también son clave en Java y se utilizan para comprobar la validez de los números. Debe comprender las operaciones bit a bit en Java, como bit a bit AND, bit a bit OR, bit a bit XOR, etc.

  4. Lista : La lista en Java se utiliza para almacenar la información de ubicación de los números que se van a completar y para emitir juicios. Necesita saber cómo operar List.

Versión C++:

  1. Clases y funciones : C++ usa clases y funciones para organizar el código. Necesita saber cómo definir clases, funciones y cómo realizar operaciones de datos en clases.

  2. Recursividad : la versión C++ también utiliza la recursividad de búsqueda en profundidad (DFS) para resolver problemas de Sudoku. Es necesario comprender el concepto de recursividad y cómo implementar funciones recursivas en C++.

  3. Operaciones de bits : las operaciones de bits también son clave en C++ y se utilizan para comprobar la validez de los números. Debe comprender las operaciones bit a bit en C++, como bit a bit AND, bit a bit OR, bit a bit XOR, etc.

  4. Vector (Vector) : Vector (Vector) en C ++ es similar a una matriz dinámica, que se utiliza para almacenar la información de posición de los números que se completarán y emitirá juicios. Necesitas entender cómo manipular vectores.

En general, no importa qué lenguaje de programación utilice, dominar los conceptos y operaciones básicos de recursividad, estructuras de datos (como sectores, listas, vectores) y operaciones bit a bit son clave para resolver problemas de Sudoku. Además, es necesario comprender cómo se implementan estos conceptos y operaciones en un lenguaje de programación específico.

38. Cuenta y dice

tema

La secuencia de contar y decir es una secuencia de cadenas de dígitos definidas por la fórmula recursiva:

countAndSay(1) = “1”
countAndSay(n) es la forma en que “diría” la cadena de dígitos de countAndSay(n-1), que luego se convierte en una cadena de dígitos diferente.
Para determinar cómo se "dice" una cadena de dígitos, divídala en el número mínimo de subcadenas de modo que cada subcadena contenga exactamente un dígito único. Luego, para cada subcadena, diga el número de dígitos y luego diga el dígito. Finalmente, concatene cada uno de dichos dígitos.

Por ejemplo, el dicho y la conversión para la cadena de dígitos “3322251”:

Dado un entero positivo n, devuelve el enésimo término de la secuencia de contar y decir.

Ejemplo 1:

Entrada: n = 1
Salida: “1”
Explicación: Este es el caso base.
Ejemplo 2:

Entrada: n = 4
Salida: “1211”
Explicación:
countAndSay(1) = “1”
countAndSay(2) = diga “1” = uno 1 = “11”
countAndSay(3) = diga “11” = dos unos = “ 21”
countAndSay(4) = diga “21” = uno 2 + uno 1 = “12” + “11” = “1211”

Restricciones:

1 <= norte <= 30

La idea general del tema.

Dado un entero positivo n, genera el enésimo elemento de la secuencia de aparición.

La "secuencia de apariencia" es una secuencia de números enteros, comenzando desde el número 1, y cada elemento de la secuencia es una descripción del elemento anterior.

Puedes considerarlo como una secuencia de cadenas numéricas definidas por una fórmula recursiva:

countAndSay(1) = "1"
countAndSay(n) es una descripción de countAndSay(n-1), luego se convierte en otra cadena numérica.
Los primeros cinco elementos son los siguientes:

  1. 1
    
  2. 11
    
  3. 21
    
  4. 1211
    
  5. 111221
    

El primer elemento es el número 1
, que describe el elemento anterior. Este número es 1, que es "un 1". Está escrito como "11" para describir el
elemento anterior. Este número es 11, que es "dos unos". Está escrito como "21", que
describe el elemento anterior, este número es 21, es decir, "a 2 + a 1", registrado como "1211"
para describir el elemento anterior, este número es 1211, que es, "un 1 + un 2 + dos 1", registrado como "111221"
para describir un Para cadenas numéricas, primero divida la cadena en un número mínimo de grupos, cada grupo consta de como máximo los mismos caracteres consecutivos. Luego, para cada grupo, primero describe el número de personajes, luego describe los personajes, formando un grupo de descripción. Para convertir una descripción en una cadena numérica, concatene todos los grupos de descripción reemplazando la cantidad de caracteres en cada grupo con un número.

Por ejemplo, la descripción de la cadena numérica "3322251" es la siguiente:

Ejemplo 1:

Entrada: n = 1
Salida: "1"
Explicación: Este es un ejemplo básico.
Ejemplo 2:

Entrada: n = 4
Salida: "1211"
Explicación:
countAndSay(1) = "1"
countAndSay(2) = leer "1" = uno 1 = "11"
countAndSay(3) = leer "11" = dos 1 = " 21"
countAndSay(4) = leer "21" = a 2 + a 1 = "12" + "11" = "1211"

pista:

1 <= norte <= 30

Ideas para resolver problemas

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. Función de justificación : esta función se utiliza para generar la siguiente secuencia de contar y decir. Atraviesa la cadena de entrada s, cuenta el número de caracteres idénticos consecutivos y une los números y caracteres en una nueva cadena de acuerdo con las reglas.

  2. Función countAndSay : esta función es la función principal, que genera el elemento de la secuencia de contar y decir n. Comienza desde el primer elemento, llama justifya la función en secuencia para generar la cadena del siguiente elemento, repite este proceso n-1varias veces y finalmente devuelve nla cadena del elemento.

Ideas para resolver problemas de la versión Python

  1. Función countAndSay : esta es la función principal utilizada para generar el elemento de la secuencia de contar y decir n. Si nes 1, devuelve "1" directamente; de ​​lo contrario, llama de forma recursiva para countAndSay(n-1)obtener la cadena del elemento anterior.

  2. Función doSay : esta función es responsable de generar la secuencia de contar y decir del elemento actual. Atraviesa la cadena de entrada sn, cuenta el número de caracteres idénticos adyacentes y los une en una nueva cadena de acuerdo con las reglas.

Ideas para resolver problemas de la versión Java

  1. Método de justificación : este método se utiliza para generar la siguiente secuencia de contar y decir. Atraviesa la cadena de entrada, cuenta el número de caracteres idénticos consecutivos y une los números y caracteres en una nueva cadena de acuerdo con las reglas.

  2. Método countAndSay : este es el método principal utilizado para generar el elemento de la secuencia de contar y decir n. Comienza desde el primer elemento, llama justifyal método en secuencia para generar la cadena del siguiente elemento, repite este proceso n-1varias veces y finalmente devuelve nla cadena del elemento.

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

  1. Función de solución : esta función se utiliza para generar la siguiente secuencia de contar y decir. Atraviesa la cadena de entrada s, cuenta el número de caracteres idénticos consecutivos y une los números y caracteres en una nueva cadena de acuerdo con las reglas.

  2. Función countAndSay : esta es la función principal utilizada para generar el elemento de la secuencia de contar y decir n. Comienza desde el primer elemento, llama solutiona la función en secuencia para generar la cadena del siguiente elemento, repite este proceso n-1varias veces y finalmente devuelve nla cadena del elemento.

Independientemente de la versión que se utilice, la idea central es generar de forma recursiva una secuencia de contar y decir, donde cada elemento depende del elemento anterior, y el recuento y empalme de caracteres se realizan de acuerdo con reglas. Cada versión utiliza diferentes lenguajes de programación y métodos de procesamiento de cadenas, pero las ideas para resolver problemas son las mismas.

código

Ir

func justify(s string) string {
    var result []byte
    i := 0

    for i < len(s) {
        c := s[i]
        count := 1

        // 统计连续相同字符的个数
        for i+1 < len(s) && s[i] == s[i+1] {
            count++
            i++
        }

        // 将统计结果添加到结果字符串中
        result = append(result, []byte(strconv.Itoa(count))...)
        result = append(result, c)

        i++
    }

    return string(result)
}

func countAndSay(n int) string {
    sequence := "1"

    for i := 1; i < n; i++ {
        sequence = justify(sequence)
    }

    return sequence
}

Pitón

class Solution:
    def countAndSay(self, n: int) -> str:
        # 基础情况:n=1时返回'1'
        if n == 1:
            return '1'
        
        # 递归调用,生成前一个序列
        prev_sequence = self.countAndSay(n - 1)
        
        # 调用doSay函数生成当前序列
        return self.doSay(prev_sequence)
    
    def doSay(self, sn):
        counts = []  # 存储相邻相同字符的个数
        digits = []  # 存储相邻相同字符
        n = len(sn)
        c = 1  # 初始化字符计数为1
        d = sn[0]  # 初始化当前字符为第一个字符

        for i in range(1, n):
            if sn[i] == sn[i - 1]:
                c += 1  # 如果当前字符与前一个字符相同,增加计数
            else:
                counts.append(c)  # 如果不同,将计数和字符添加到对应的列表中
                digits.append(d)
                c = 1  # 重置计数为1
                d = sn[i]  # 更新当前字符为新字符
        
        # 处理最后一组相同字符
        counts.append(c)
        digits.append(d)
        
        # 使用列表解析将计数和字符组合成字符串
        return ''.join([f'{x}{y}' for x, y in zip(counts, digits)])

Java

class Solution {
    // 定义一个方法,用于将输入的字符串进行报数
    public String justify(String s) {
        // 创建一个 StringBuilder 对象,用于存储结果
        StringBuilder result = new StringBuilder();
        // 遍历输入的字符串
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i); // 获取当前字符
            int sum = 1; // 初始化计数器为 1,表示至少有一个当前字符

            // 如果当前字符是输入字符串的最后一个字符或者与下一个字符不同
            if (i + 1 >= s.length() || c != s.charAt(i + 1)) {
                result.append(sum); // 将计数器的值追加到结果中
                result.append(c);   // 将当前字符追加到结果中
                return String.valueOf(result); // 返回结果的字符串表示
            }

            // 如果当前字符与下一个字符相同,继续遍历并增加计数器
            while (c == s.charAt(i + 1)) {
                sum++;
                i++;

                // 如果当前字符是输入字符串的最后一个字符,将计数器的值和字符追加到结果中,并返回
                if (i + 1 >= s.length()) {
                    result.append(sum);
                    result.append(c);
                    return String.valueOf(result);
                }
            }

            // 将计数器的值和字符追加到结果中
            result.append(sum);
            result.append(c);
        }

        // 返回结果的字符串表示
        return String.valueOf(result);
    }

    // 定义一个方法,根据输入的 n 返回第 n 个报数序列
    public String countAndSay(int n) {
        String[] list = new String[n];
        list[0] = "1"; // 第一个序列是固定的 "1"
        
        // 生成第 2 到第 n 个序列
        for (int i = 1; i < n; i++) {
            String s = list[i - 1]; // 获取前一个序列
            list[i] = justify(s); // 生成当前序列并保存
        }
        
        // 返回第 n 个序列
        return list[n - 1];
    }
}

cpp

#include <iostream>
#include <string>

class Solution {
public:
    string countAndSay(int n) {
        string s = "1"; // 初始序列为 "1"
        for (int i = 1; i < n; ++i) {
            solution(s); // 调用 solution 函数生成下一个序列
            std::cout << "s:" << s << std::endl; // 可选:打印当前序列,用于调试
        }
        return s; // 返回第 n 个报数序列
    }

    void solution(string &s) {
        string ans; // 用于存储生成的下一个序列
        int l = 0, r = 0; // 左右指针,用于统计相同字符的个数

        while (r < s.size()) {
            if (s[r] == s[l]) {
                r++; // 同字符,右指针移动
                continue;
            }

            int cnt = r - l; // 统计相同字符的个数
            ans.push_back(cnt + '0'); // 将个数添加到结果字符串
            ans.push_back(s[l]); // 添加字符本身
            l = r; // 左指针移到右指针位置
        }

        int cnt = r - l; // 处理末尾相同字符
        ans.push_back(cnt + '0');
        ans.push_back(s[l]);

        s = ans; // 更新原始字符串为下一个序列
    }
};

Cuando utilizamos diferentes lenguajes de programación para resolver el mismo problema, necesitamos conocer la sintaxis específica y las funciones de biblioteca de cada lenguaje, pero al resolver este problema específico, necesitamos dominar algunos conocimientos básicos comunes. A continuación se muestran los conceptos básicos detallados de cada versión:

Ir versión

  • Declaración y llamada de funciones : aprenda a declarar y llamar funciones, así como sus parámetros y valores de retorno.
  • Manejo de cadenas : las cadenas son inmutables en Go, por lo que es necesario comprender cómo realizar operaciones en cadenas inmutables y cómo convertir cadenas en matrices de bytes y viceversa.
  • Bucles y declaraciones condicionales : aprenda a utilizar bucles y declaraciones condicionales para controlar el flujo de su programa.
  • Sector : los sectores son matrices dinámicas y es necesario saber cómo crearlos y operarlos.
  • Entero a cadena : un método para convertir números enteros en cadenas en Go.

Versión de Python

  • Clases y métodos : Python es un lenguaje orientado a objetos, comprenda cómo definir clases y métodos.
  • Recursividad : para resolver este problema, la recursividad se utiliza para generar el siguiente elemento de la secuencia.
  • Operaciones de cadenas : Python proporciona una gran cantidad de métodos de operación de cadenas, como indexación, división y concatenación de cadenas.
  • Comprensión de listas : la comprensión de listas en Python es una forma rápida de generar listas, útil para manejar el recuento y la concatenación de caracteres.

versión java

  • Clases y métodos : Java es un lenguaje orientado a objetos, comprenda cómo definir clases y métodos y cómo usarlos para organizar el código.
  • Recursividad : al igual que la versión de Python, la versión de Java también utiliza la recursividad para generar secuencias.
  • Operaciones de cadena : Java proporciona varios métodos de operación de cadenas, como charAt, length, etc.
  • Clase StringBuilder : en Java, utilice la clase StringBuilder para crear y manipular cadenas mutables para mejorar el rendimiento.

versión C++

  • Clases y métodos : C++ también admite programación orientada a objetos, aprenda a definir clases y funciones miembro.
  • Recursividad : al igual que las versiones de Python y Java, la versión C++ también utiliza la recursividad para generar secuencias.
  • Operaciones de cadena : C++ proporciona la clase de cadena en la biblioteca estándar, aprenda a usarla para procesar cadenas.
  • Conversión de caracteres : utilice funciones de conversión de caracteres para convertir números enteros en caracteres.

39. Suma combinada

tema

Dado un conjunto de números candidatos ( candidates) (sin duplicados) y un número objetivo ( target), encuentre todas las combinaciones únicas en candidateslas que la suma de los números candidatos sea target.

Se podrá elegir el mismocandidates número repetido entre un número ilimitado de veces.

Nota:

  • Todos los números (incluido target) serán números enteros positivos.
  • El conjunto de soluciones no debe contener combinaciones duplicadas.

Ejemplo 1:

Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Ejemplo 2:

Input: candidates = [2,3,5], target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

La idea general del tema.

Dada una serie de candidatos sin elementos duplicados y un número objetivo, encuentre todas las combinaciones en los candidatos que puedan hacer que la suma de los números sea el objetivo.

Los números de candidatos se pueden seleccionar repetidamente sin límite.

Ideas para resolver problemas

La siguiente es una introducción detallada a las ideas de resolución de problemas para cada versión:

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

  1. Inicialización de sectores : cree dos sectores retpara almacenar el resultado final y valsun valor temporal para la combinación actual.

  2. Clasificacióncandidates : Ordene la colección candidata en orden ascendente, de modo que el uso de elementos se pueda controlar más convenientemente en búsquedas posteriores.

  3. Búsqueda recursiva : defina backtrackinguna función recursiva denominada , que tiene tres parámetros: startindicar la posición en el conjunto de números candidatos desde donde comenzar la búsqueda e sumindicar la suma de elementos de la combinación actual.

  4. Lógica de búsqueda recursiva : backtrackingdentro de la función, primero verifique sumsi es igual a 0. Si es igual a 0, significa que se encuentra una combinación que cumple la condición, la combinación actual se valscopia en un segmento temporal y el segmento se agrega al resultado ret.

  5. Recorrer el conjunto de números candidatos: utilice un bucle para recorrer el conjunto de números candidatos, comenzando desde starty considere cada número candidato uno por uno.

    • Si el número actual de candidatos es mayor sum, significa que el número de candidatos posteriores también debe ser mayor sum, para que el ciclo (poda) pueda finalizar antes de tiempo.
    • De lo contrario, agregue el número actual de candidatos a la combinación actual valsy luego llame backtrackinga la función de forma recursiva para continuar la búsqueda.
    • Después de que regrese la recursividad, debe retroceder, es decir, valseliminar para probar otras combinaciones.
  6. Llame a la función recursiva : Finalmente, combinationSumllame backtrackinga la función dentro de la función para comenzar a buscar una combinación.

  7. Devolver resultados : devuelve todas las combinaciones encontradas, es decir, retsectores.

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, utilizando métodos recursivos de retroceso y clasificación similares, pero la sintaxis del código y las operaciones de lista son ligeramente diferentes. Las ideas principales incluyen:

  1. Inicialización de lista : cree dos listas resultpara almacenar el resultado final y currentun valor temporal para la combinación actual.

  2. Ordenar : Ordena la lista de candidatos candidatespara que sea más fácil controlar el uso de elementos en búsquedas posteriores.

  3. Búsqueda recursiva : defina backtrackuna función recursiva denominada , que tiene cinco parámetros: resultse usa para almacenar los resultados, currentse usa para almacenar la combinación actual, candidatesuna lista de candidatos ordenada, targetla suma objetivo y startla posición inicial de la búsqueda actual.

  4. Lógica de búsqueda recursiva : backtrackdentro de la función, primero verifique targetsi es igual a 0. Si es igual a 0, significa que se encuentra una combinación que cumple la condición y la combinación actual currentse suma al resultado result.

  5. Recorrer la lista de números candidatos : utilice un bucle para recorrer la lista de números candidatos, comenzando desde starty considere cada número candidato uno por uno.

    • Si el número actual de candidatos es menor o igual a target, agregue el número actual de candidatos a la combinación actual currenty luego llame backtracka la función de forma recursiva para continuar la búsqueda.
    • Después de que regrese la recursividad, debe retroceder, es decir, currenteliminar para probar otras combinaciones.
  6. Llamar a una función recursiva : combinationSumllame backtracka la función dentro de la función para comenzar a buscar una combinación.

  7. Devolver resultados : Devuelve todas las combinaciones encontradas, es decir, resultuna lista.

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

Las ideas de resolución de problemas de la versión Java son similares a las de la versión Python, pero la de Java se utiliza ArrayListpara almacenar los resultados y la combinación actual, así como la convención de nomenclatura de métodos de Java. Las ideas principales incluyen:

  1. Inicialización de ArrayList : cree dos ArrayListpara resultalmacenar el resultado final y currentuno para almacenar el valor temporal de la combinación actual.

  2. Ordenar : Ordena la matriz candidata candidatespara que sea más fácil controlar el uso de elementos en búsquedas posteriores.

  3. Búsqueda recursiva : defina backtrackuna función recursiva denominada, que tiene cinco parámetros: resultse usa para almacenar los resultados, currentse usa para almacenar la combinación actual, candidatesla matriz candidata ordenada, targetla suma objetivo y startla posición inicial de la búsqueda actual.

  4. Lógica de búsqueda recursiva : backtrackdentro de la función, primero verifique targetsi es igual a 0. Si es igual a 0, significa que se encuentra una combinación que cumple la condición y la combinación actual currentse suma al resultado result.

  5. Recorrer la matriz de números candidatos : utilice un bucle para recorrer la matriz de números candidatos, comenzando desde starty considere cada número candidato uno por uno.

    • Si el número actual de candidatos es menor o igual a target, agregue el número actual de candidatos a la combinación actual currenty luego llame backtracka la función de forma recursiva para continuar la búsqueda.
    • Después de que regrese la recursividad, debe retroceder, es decir, currenteliminar para probar otras combinaciones.
  6. Llamar a una función recursiva : combinationSumllame backtracka la función dentro de la función para comenzar a buscar una combinación.

  7. Resultados de retorno : Devuelve todas las combinaciones encontradas, es decir, resultuna `ArrayList de

código

Ir

func combinationSum(candidates []int, target int) [][]int {
    ret := [][]int{}            // 用于存储结果的二维切片
    vals := []int{}             // 用于存储当前组合的切片
    var backtraking func(candidates []int, start, sum int) // 递归函数的声明

    sort.Ints(candidates)        // 对候选数集合进行升序排序

    // 定义递归函数,该函数用于搜索组合
    backtraking = func(candidates []int, start, sum int) {
        if sum == 0 {
            tmp := make([]int, len(vals))  // 创建一个临时切片以存储当前组合
            copy(tmp, vals)                 // 将当前组合复制到临时切片中
            ret = append(ret, tmp)          // 将临时切片添加到结果中
            return
        }

        for i := start; i < len(candidates); i++ {
            if candidates[i] > sum {
                break
            }
            vals = append(vals, candidates[i])     // 将当前候选数添加到组合中
            backtraking(candidates, i, sum-candidates[i]) // 递归调用函数,继续搜索
            vals = vals[:len(vals)-1]               // 回溯,将最后一个元素从组合中移除
        }
    }

    backtraking(candidates, 0, target) // 调用递归函数来开始搜索组合

    return ret // 返回找到的所有组合
}

Pitón

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        def backtrack(result, current, candidates, target, start):
            if target == 0:
                result.append(list(current))
                return
            
            for i in range(start, len(candidates)):
                if candidates[i] <= target:
                    current.append(candidates[i])
                    backtrack(result, current, candidates, target - candidates[i], i)
                    current.pop()
        
        result = []
        current = []
        
        # 对候选数列表进行排序
        candidates.sort()
        
        # 调用回溯函数
        backtrack(result, current, candidates, target, 0)
        
        return result

Java

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

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> current = new ArrayList<>();
        
        // 对候选数列表进行排序
        Arrays.sort(candidates);
        
        // 调用回溯函数
        backtrack(result, current, candidates, target, 0);
        
        return result;
    }
    
    private void backtrack(List<List<Integer>> result, List<Integer> current, int[] candidates, int target, int start) {
        if (target == 0) {
            result.add(new ArrayList<>(current));
            return;
        }
        
        for (int i = start; i < candidates.length && candidates[i] <= target; i++) {
            current.add(candidates[i]);
            backtrack(result, current, candidates, target - candidates[i], i);
            current.remove(current.size() - 1);
        }
    }
}

cpp

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> result;
        vector<int> current;
        
        // 对候选数列表进行排序
        sort(candidates.begin(), candidates.end());
        
        // 调用回溯函数
        backtrack(result, current, candidates, target, 0);
        
        return result;
    }
    
    void backtrack(vector<vector<int>>& result, vector<int>& current, vector<int>& candidates, int target, int start) {
        if (target == 0) {
            result.push_back(current);
            return;
        }
        
        for (int i = start; i < candidates.size() && candidates[i] <= target; i++) {
            current.push_back(candidates[i]);
            backtrack(result, current, candidates, target - candidates[i], i);
            current.pop_back();
        }
    }
};

Cuando lo presentemos en chino, presentaremos el código de cada versión (Go, Python, Java y C++) y los conocimientos básicos necesarios para comprender el código:

Ir versión:

  1. Sectores : los sectores en Go son matrices dinámicas cuya longitud puede crecer según sea necesario. En este código, valsy retson ambos segmentos, que se utilizan para almacenar los datos temporales combinados y el resultado final.

  2. Recursividad : el código utiliza la recursividad para buscar posibles combinaciones. Comprender cómo funciona la recursividad y cómo escribir funciones recursivas es importante para comprender este código.

  3. Clasificación : antes de iniciar la búsqueda combinatoria, el código ordena la matriz candidata. Es necesario comprender el algoritmo de clasificación y cómo ordenar en Go.

  4. Operaciones de corte : el código utiliza operaciones de corte, como appendla intercepción de corte, para procesar elementos combinados.

Versión de Python:

  1. Listas : las listas en Python se utilizan para almacenar múltiples valores. En este código, resulty currentse utilizan ambas listas para almacenar los datos temporales combinados y el resultado final.

  2. Recursividad : el código utiliza la recursividad para buscar posibles combinaciones. Comprender cómo funciona la recursividad y cómo escribir funciones recursivas es importante para comprender este código.

  3. Clasificación : antes de iniciar la búsqueda combinatoria, el código ordena la matriz candidata. Es necesario comprender el algoritmo de clasificación y cómo ordenar en Python.

  4. Operaciones de lista : el código utiliza operaciones de lista, como appendy pop, para procesar elementos combinados.

Versión de Java:

  1. Listas : puede utilizar ArrayListotras listas en Java para almacenar varios valores. En este código, resulty currentse ArrayListutilizan para almacenar los datos temporales combinados y el resultado final.

  2. Recursividad : el código utiliza la recursividad para buscar posibles combinaciones. Comprender cómo funciona la recursividad y cómo escribir funciones recursivas es importante para comprender este código.

  3. Clasificación : antes de iniciar la búsqueda combinatoria, el código ordena la matriz candidata. Es necesario comprender el algoritmo de clasificación y cómo realizar la clasificación en Java.

  4. Operaciones de lista : el código utiliza operaciones de lista, como addy remove, para procesar elementos combinados.

Versión C++:

  1. Vectores : utilizados en C++ vectorpara almacenar múltiples valores. En este código, resulty currentse vectorutilizan para almacenar los datos temporales combinados y el resultado final.

  2. Recursividad : el código utiliza la recursividad para buscar posibles combinaciones. Comprender cómo funciona la recursividad y cómo escribir funciones recursivas es importante para comprender este código.

  3. Clasificación : antes de iniciar la búsqueda combinatoria, el código ordena la matriz candidata. Es necesario comprender el algoritmo de clasificación y cómo realizar la clasificación en C++.

  4. Operaciones vectoriales : el código utiliza operaciones vectoriales, como push_backy pop_back, para procesar los elementos combinados.

Además de comprender estos códigos, también debe comprender los conceptos básicos de la recursividad, los algoritmos de clasificación y las estructuras de datos (como listas o sectores) para comprender y modificar mejor estos códigos.

40. Suma combinada II

tema

Dada una colección de números candidatos ( candidates) y un número objetivo ( target), encuentre todas las combinaciones únicas
en candidateslas que la suma de los números candidatos sea target.

Cada número candidatessolo se puede utilizar una vez en la combinación.

Nota:

  • Todos los números (incluido target) serán números enteros positivos.
  • El conjunto de soluciones no debe contener combinaciones duplicadas.

Ejemplo 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Ejemplo 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]

La idea general del tema.

Dada una serie de candidatos y un número objetivo, encuentre todas las combinaciones en los candidatos que puedan hacer que la suma de los números sea el objetivo.

Cada número de los candidatos solo se puede utilizar una vez en cada combinación.

Ideas para resolver problemas

Ir a la versión de ideas para resolver problemas

  1. Ordene la matriz candidatacandidates : primero, ordene la matriz dada . Esto es para facilitar las operaciones de deduplicación posteriores, y los elementos idénticos se dispondrán adyacentes.

  2. Buscar mediante recursividad : utilice una función recursiva findcombinationSum2para buscar combinaciones que coincidan con los criterios. Los parámetros de la función incluyen la candidatesmatriz actual, el valor objetivo target, la posición inicial de la búsqueda actual index, la combinación que se está construyendo actualmente cy la lista de resultados res.

  3. Búsqueda recursiva : en una búsqueda recursiva, primero se verifica si se ha alcanzado el valor objetivo targety, de ser así, cse agrega la combinación actual a la lista de resultados res.

  4. Recorre el número de candidatos : recorre candidateslos elementos de la matriz, indexcomenzando desde el actual. Durante el proceso transversal, preste atención a la operación de deduplicación, si el elemento actual es el mismo que el elemento anterior, omítalo para evitar combinaciones repetidas.

  5. Cree una combinación : para cada candidato legal, agréguelo a la combinación actual cy actualice el valor objetivo target. Luego, findcombinationSum2se llama a la función de forma recursiva para continuar la búsqueda.

  6. Operación de retroceso : después de que regresa la llamada recursiva, se requiere una operación de retroceso para sacar el último número de candidatos agregados de la combinación actual cpara continuar buscando otras combinaciones posibles.

  7. Devolver resultados : finalmente, se devuelve una lista de resultados res, que contiene todas las combinaciones únicas que cumplen las condiciones.

Ideas para resolver problemas de la versión Python

Las ideas de resolución de problemas de la versión Python son similares a las de la versión Go, pero se utilizan funciones y sintaxis específicas de Python. Aquí están las ideas para resolver el problema:

  1. Ordenar la matriz candidatacandidates : Primero, ordene la lista dada . Esto es para facilitar las operaciones de deduplicación posteriores, y los elementos idénticos se dispondrán adyacentes.

  2. Buscar mediante recursividad : utilice una función recursiva dfspara buscar combinaciones que coincidan con los criterios. Los parámetros de la función incluyen la candidateslista actual, el valor objetivo target, la posición inicial de la búsqueda actual start, la combinación que se está construyendo actualmente suby la lista de resultados res.

  3. Búsqueda recursiva : en una búsqueda recursiva, primero se verifica si se ha alcanzado el valor objetivo targety, de ser así, subse agrega la combinación actual a la lista de resultados res.

  4. Recorre el número de candidatos : recorre candidateslos elementos de la lista, startcomenzando desde el actual. Durante el proceso transversal, preste atención a la operación de deduplicación, si el elemento actual es el mismo que el elemento anterior, omítalo para evitar combinaciones repetidas.

  5. Cree una combinación : para cada candidato legal, agréguelo a la combinación actual suby actualice el valor objetivo target. Luego, dfsse llama a la función de forma recursiva para continuar la búsqueda.

  6. Operación de retroceso : después de que regresa la llamada recursiva, se requiere una operación de retroceso para sacar el último número de candidatos agregados de la combinación actual subpara continuar buscando otras combinaciones posibles.

  7. Devolver resultados : finalmente, se devuelve una lista de resultados res, que contiene todas las combinaciones únicas que cumplen las condiciones.

Ideas para resolver problemas de la versión Java

Las ideas de resolución de problemas de la versión Java son similares a las de la versión Python, pero se utilizan clases de colección y sintaxis específicas de Java. Aquí están las ideas para resolver el problema:

  1. Ordene la matriz candidatacandidates : primero, ordene la matriz dada . Esto es para facilitar las operaciones de deduplicación posteriores, y los elementos idénticos se dispondrán adyacentes.

  2. Buscar usando una clase interna anónima : use una clase interna anónima para implementar AbstractListla interfaz, que anula los métodos gety sizepara lograr una generación diferida de la lista de resultados.

  3. Búsqueda recursiva : en la búsqueda recursiva, primero se verifica si se ha alcanzado el valor objetivo targety, de ser así, se agrega la combinación actual a la lista de resultados.

  4. Recorre el número de candidatos : recorre candidateslos elementos de la matriz, comenzando desde la posición inicial actual. Durante el proceso transversal, preste atención a la operación de deduplicación, si el elemento actual es el mismo que el elemento anterior, omítalo para evitar combinaciones repetidas.

  5. Construya una combinación : para cada número de candidato legal, agréguelo a la combinación actual y actualice el valor objetivo. Luego, se llama recursivamente a la función de búsqueda para continuar la búsqueda.

  6. Operación de retroceso : después de que regresa la llamada recursiva, se requiere una operación de retroceso para sacar el último número de candidatos agregados de la combinación actual para continuar buscando otras combinaciones posibles.

  7. Devolver resultados : finalmente, se devuelve una lista de resultados, que contiene todas las combinaciones únicas que cumplen las condiciones.

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

Las ideas de resolución de problemas de la versión C++ son similares a las de la versión Python, pero se utilizan la sintaxis específica de C++ y las funciones de biblioteca estándar. Aquí están las ideas para resolver el problema:

  1. Ordenar la matriz candidatacandidates : Primero, ordene el vector dado . Esto es para facilitar las operaciones de deduplicación posteriores, y los elementos idénticos se dispondrán adyacentes.

  2. Búsqueda mediante recursividad (continuación) : en la búsqueda recursiva, primero verifique si se ha alcanzado el valor objetivo target; de ser así, agregue la combinación actual currentCombinational vector de resultados result.

  3. Recorre el número de candidatos : recorre candidateslos elementos del vector, indexcomenzando desde el actual. Durante el proceso transversal, preste atención a la operación de deduplicación, si el elemento actual es el mismo que el elemento anterior, omítalo para evitar combinaciones repetidas.

  4. Cree una combinación : para cada candidato legal, agréguelo a la combinación actual currentCombinationy actualice el valor objetivo target. Luego, findCombinationSum2se llama a la función de forma recursiva para continuar la búsqueda.

  5. Operación de retroceso : después de que regresa la llamada recursiva, se requiere una operación de retroceso para sacar el último número de candidatos agregados de la combinación actual currentCombinationpara continuar buscando otras combinaciones posibles.

  6. Resultado de retorno : Finalmente, se devuelve el vector de resultado result, que contiene todas las combinaciones únicas que cumplen las condiciones.

código

Ir

import (
    "sort"
)

func combinationSum2(candidates []int, target int) [][]int {
    if len(candidates) == 0 {
        return [][]int{}
    }
    c, res := []int{}, [][]int{}
    sort.Ints(candidates) // 这里是去重的关键逻辑
    findcombinationSum2(candidates, target, 0, c, &res)
    return res
}

func findcombinationSum2(nums []int, target, index int, c []int, res *[][]int) {
    if target == 0 {
        b := make([]int, len(c))
        copy(b, c)
        *res = append(*res, b)
        return
    }
    for i := index; i < len(nums); i++ {
        if i > index && nums[i] == nums[i-1] { // 这里是去重的关键逻辑,本次不取重复数字,下次循环可能会取重复数字
            continue
        }
        if target >= nums[i] {
            c = append(c, nums[i])
            findcombinationSum2(nums, target-nums[i], i+1, c, res)
            c = c[:len(c)-1]
        }
    }
}

Pitón

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()  # 对候选数组进行排序,以便去重
        res = []  # 用于存储最终结果的列表

        def dfs(candidates, start, sub, subTarget):
            if subTarget == 0:  # 当子目标值为0时,表示找到了一个组合
                res.append(sub)
                return
            if subTarget < 0:  # 当子目标值小于0时,不符合条件,直接返回
                return

            for i in range(start, len(candidates)):
                if candidates[i] > subTarget:
                    break  # 剪枝:如果当前候选数大于子目标值,跳出循环
                if i > start and candidates[i] == candidates[i - 1]:
                    continue  # 去重逻辑:跳过重复的候选数

                # 递归调用,尝试将当前候选数加入子组合,并更新子目标值和下一次搜索的起始位置
                dfs(candidates, i + 1, sub + [candidates[i]], subTarget - candidates[i])

        dfs(candidates, 0, [], target)  # 初始调用 DFS
        return res  # 返回最终结果

Java

import java.util.AbstractList;

class Solution {
    public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
        return new AbstractList<List<Integer>>() { // 创建一个继承自 AbstractList 的匿名内部类
            private final List<List<Integer>> list = new ArrayList<>(); // 存储最终结果的列表
            private final List<Integer> comb = new ArrayList<>(); // 存储当前组合的列表

            @Override
            public List<Integer> get(int index) {
                init(); // 初始化,确保结果列表已经生成
                return list.get(index); // 返回指定索引处的组合
            }

            @Override
            public int size() {
                init(); // 初始化,确保结果列表已经生成
                return list.size(); // 返回结果列表的大小
            }

            public void init() {
                if (list.isEmpty()) { // 如果结果列表为空,进行初始化操作
                    Arrays.sort(candidates); // 对候选数组进行排序,以便进行去重和优化
                    getComb(target, 0); // 调用递归函数生成组合
                }
            }

            public void getComb(int target, int beginIndex) {
                if (target == 0) { // 当目标值为0时,表示找到一个组合
                    list.add(new ArrayList<>(comb)); // 将当前组合添加到结果列表中
                    return;
                }
                for (int i = beginIndex; i < candidates.length; i++) {
                    if (candidates[i] > target) {
                        return; // 剪枝:如果当前候选数大于目标值,直接返回,不再继续搜索
                    }
                    comb.add(candidates[i]); // 将当前候选数加入组合
                    getComb(target - candidates[i], i + 1); // 递归调用,更新目标值和起始位置
                    comb.remove(comb.size() - 1); // 回溯,移除最后一个候选数
                    while (i + 1 < candidates.length && candidates[i + 1] == candidates[i]) {
                        i++; // 去重逻辑:跳过重复的候选数
                    }
                }
            }
        };
    }
}

cpp

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> result; // 存储最终结果的二维向量
        vector<int> currentCombination; // 存储当前组合的一维向量

        if (candidates.empty()) {
            return result; // 如果候选数组为空,直接返回空结果
        }

        sort(candidates.begin(), candidates.end()); // 对候选数组进行排序,以便进行去重和优化
        findCombinationSum2(candidates, target, 0, currentCombination, result); // 调用递归函数生成组合

        return result;
    }

private:
    void findCombinationSum2(vector<int>& candidates, int target, int index, vector<int>& currentCombination, vector<vector<int>>& result) {
        if (target == 0) { // 当目标值为0时,表示找到一个组合
            result.push_back(currentCombination); // 将当前组合添加到结果中
            return;
        }

        for (int i = index; i < candidates.size(); i++) {
            if (i > index && candidates[i] == candidates[i - 1]) {
                continue; // 去重逻辑:跳过重复元素
            }

            if (target >= candidates[i]) {
                currentCombination.push_back(candidates[i]); // 添加当前候选数到组合中
                findCombinationSum2(candidates, target - candidates[i], i + 1, currentCombination, result); // 递归调用,更新目标值和起始位置
                currentCombination.pop_back(); // 回溯,移除当前候选数
            }
        }
    }
};

Explicaré en detalle los requisitos de conocimientos básicos para cada lenguaje de programación mientras cubrimos cada versión del código por separado. Aquí hay una descripción de cada versión:

Ir versión

Go es un lenguaje de programación de tipo estático. Si desea comprender la versión Go del código, debe dominar los siguientes conocimientos básicos:

  1. Variables y tipos de datos : aprenda a declarar variables y utilizar diferentes tipos de datos, como enteros, sectores, matrices y sectores.

  2. Funciones : aprenda a definir y llamar funciones, así como sus parámetros y valores de retorno.

  3. Sectores y matrices : obtenga información sobre sectores y matrices en Go, que se utilizan en este código para almacenar combinaciones.

  4. Recursividad : comprenda el concepto y el funcionamiento de la recursividad a medida que el código la utiliza para encontrar combinaciones.

  5. Clasificación : Comprenda cómo sortordenar porciones para la deduplicación utilizando el paquete.

  6. Bucles y declaraciones condicionales : comprenda cómo utilizar bucles y declaraciones condicionales para controlar el flujo de un programa.

Versión de Python

Python es un lenguaje de programación simple pero poderoso. Si desea comprender la versión Python del código, debe dominar los siguientes conocimientos básicos:

  1. Variables y tipos de datos : aprenda a declarar variables y utilizar diferentes tipos de datos, como números enteros, listas, tuplas, etc.

  2. Funciones : aprenda a definir y llamar funciones, así como sus parámetros y valores de retorno.

  3. Listas : obtenga información sobre las listas en Python, se utilizan en este código para almacenar combinaciones.

  4. Recursividad : comprenda el concepto y el funcionamiento de la recursividad a medida que el código la utiliza para encontrar combinaciones.

  5. Clasificación : aprenda a utilizar sortedla función para ordenar una lista y eliminar duplicados.

  6. Bucles y declaraciones condicionales : comprenda cómo utilizar bucles y declaraciones condicionales para controlar el flujo de un programa.

versión java

  1. Clases y objetos : aprenda a definir clases y crear objetos, ya que Java es un lenguaje orientado a objetos.

  2. Métodos : aprenda a definir y llamar métodos, así como sus parámetros y valores de retorno.

  3. Listas y conjuntos : obtenga información sobre las listas y conjuntos en Java, que se utilizan en este código para almacenar combinaciones.

  4. Recursividad : comprenda el concepto y el funcionamiento de la recursividad a medida que el código la utiliza para encontrar combinaciones.

  5. Clasificación : aprenda a Collections.sortordenar una lista utilizando el método para eliminar duplicados.

  6. Bucles y declaraciones condicionales : comprenda cómo utilizar bucles y declaraciones condicionales para controlar el flujo de un programa.

versión C++

C ++ es un lenguaje de programación multiparadigma. Si desea comprender la versión C ++ del código, debe dominar los siguientes conocimientos básicos:

  1. Variables y tipos de datos : aprenda a declarar variables y utilizar diferentes tipos de datos, como enteros, vectores, matrices, etc.

  2. Funciones : aprenda a definir y llamar funciones, así como sus parámetros y valores de retorno.

  3. Vectores y matrices : obtenga información sobre los vectores y matrices en C++, que se utilizan en este código para almacenar combinaciones.

  4. Recursividad : comprenda el concepto y el funcionamiento de la recursividad a medida que el código la utiliza para encontrar combinaciones.

  5. Clasificación : aprenda a sortordenar vectores para la deduplicación utilizando las funciones de la biblioteca estándar.

  6. Bucles y declaraciones condicionales : comprenda cómo utilizar bucles y declaraciones condicionales para controlar el flujo de un programa.

Los anteriores son los requisitos de conocimientos básicos necesarios para cada versión del código. Puede elegir una de las versiones según su preferencia de lenguaje de programación y obtener más información sobre las características relevantes del lenguaje y las funciones de la biblioteca para comprender y modificar mejor su código.

41. Primer Positivo Faltante

tema

Dada una matriz de enteros sin clasificar, encuentre el entero positivo más pequeño que falta.

Ejemplo 1:

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

Ejemplo 2:

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

Ejemplo 3:

Input: [7,8,9,11,12]  
Output: 1  

Nota:

Su algoritmo debe ejecutarse en tiempo O(n) y utiliza espacio adicional constante.

La idea general del tema.

Encuentra el primer número entero positivo que falta.

Ideas para resolver problemas

Ir solución :

La idea detrás de esta solución es la siguiente:

  1. Primero, recorra la matriz y coloque los números enteros positivos donde deberían estar. Lo que esto hace es, para cada elemento de la matriz nums[i], si es un número entero positivo y está en el rango válido (1 an), colocarlo en la nums[i] - 1posición con índice. De esta forma se marca correctamente la posición donde debe estar el número entero positivo en la matriz.

  2. Luego, repita la matriz nuevamente y encuentre el primer entero positivo que no está en la posición correcta, es decir, el primer entero positivo que falta. Si se encuentra un entero positivo durante el recorrido, se devuelve. Si no se encuentra a nadie después de atravesar la matriz, significa que la matriz contiene todos los números enteros positivos y luego devuelve len(nums) + 1el siguiente entero positivo.

  3. Esta solución también incluye una función recursiva changeArrayque maneja el proceso de intercambio de elementos.

Solución de Python :

La idea detrás de esta solución es la siguiente:

  1. Primero, almacene todos los elementos de la matriz en un conjunto para una búsqueda rápida.

  2. Luego, verifique los números enteros positivos uno por uno comenzando desde 1. Si no hay un entero positivo en el conjunto, es el primer entero positivo que falta y se devuelve directamente.

  3. Si no se encuentra ningún entero positivo faltante después de recorrer todos los enteros positivos, significa que la matriz contiene todos los enteros positivos y devuelve n + 1, donde nestá la longitud de la matriz.

solución Java :

La idea detrás de esta solución es la siguiente:

  1. Cree una matriz booleana numExistspara marcar la presencia de números enteros positivos. La longitud de la matriz es nums.length + 1. Cuando se inicializa, todos los elementos son false.

  2. Recorra la matriz y marque la posición numscorrespondiente al entero positivo en la matriz .numExiststrue

  3. Recorra numExistsla matriz nuevamente y encuentre la primera trueposición no marcada como, que es el primer entero positivo que falta.

  4. Si no se encuentra a nadie después de atravesar numExistsla matriz, significa que la matriz contiene todos los números enteros positivos y devuelve nums.length + 1.

Solución C++ :

La idea detrás de esta solución es la siguiente:

  1. Primero, recorra la matriz y coloque los números enteros positivos donde deberían estar. Lo que esto hace es, para cada elemento de la matriz nums[i], si es un número entero positivo y está en el rango válido (1 an), colocarlo en la nums[i] - 1posición con índice. De esta forma se marca correctamente la posición donde debe estar el número entero positivo en la matriz.

  2. Luego, repita la matriz nuevamente y encuentre el primer entero positivo que no está en la posición correcta, es decir, el primer entero positivo que falta. Si se encuentra un entero positivo durante el recorrido, se devuelve. Si no se encuentra a nadie después de atravesar la matriz, significa que la matriz contiene todos los números enteros positivos y luego devuelve n + 1el siguiente entero positivo.

código

Ir

func firstMissingPositive(nums []int) int {
    for i := 0; i < len(nums); i++ {
        if nums[i] > 0 && nums[i] <= len(nums) && nums[i] != i+1 {
            tmp := nums[nums[i]-1]
            nums[nums[i]-1] = nums[i]
            if tmp == i+1 || tmp <= 0 || tmp > len(nums) {
                nums[i] = tmp
            } else {
                if tmp > 0 && tmp <= len(nums) && tmp != nums[tmp-1] {
                    tmp = changeArray(nums, tmp)
                } else {
                    nums[i] = tmp
                }
            }
        }
    }
    
    for i := 0; i < len(nums); i++ {
        if nums[i] != i+1 {
            return i + 1
        }
    }
    
    return len(nums) + 1
}

func changeArray(nums []int, tmp int) int {
    if tmp <= 0 || tmp > len(nums) || tmp == nums[tmp-1] {
        return tmp
    }
    nextTmp := nums[tmp-1]
    nums[tmp-1] = tmp
    return changeArray(nums, nextTmp)
}

Pitón

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        # 使用集合来存储数组中的元素,以便快速查找
        s = set(nums)
        n = len(nums)
        
        # 从1开始逐个检查正整数,如果某个正整数不在集合中,即为缺失的第一个正整数
        for i in range(1, n + 1):
            if i not in s:
                return i
        
        # 如果数组中包含所有正整数,则返回 n+1
        return n + 1

Java

class Solution {
    public int firstMissingPositive(int[] nums) {
        // 创建一个映射(数组),用于存储正整数的存在情况
        boolean[] numExists = new boolean[nums.length + 1];
        
        // 将数组中的正整数标记在映射中
        for (int num : nums) {
            if (num > 0 && num <= nums.length) {
                numExists[num] = true;
            }
        }
        
        // 从1开始逐个检查映射,找到第一个未标记的正整数即为缺失的第一个正整数
        for (int i = 1; i < numExists.length; i++) {
            if (!numExists[i]) {
                return i;
            }
        }
        
        // 如果数组中包含所有正整数,则返回数组长度加1作为缺失的第一个正整数
        return nums.length + 1;
    }
}

cpp

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();

        // 遍历数组,将每个正整数 nums[i] 放置到其应该在的位置 nums[nums[i]-1]
        for (int i = 0; i < n; ) {
            // 检查 nums[i] 是否是一个有效的正整数,并且是否不在正确的位置上
            if (nums[i] > 0 && nums[i] < n && nums[i] != nums[nums[i] - 1]) {
                swap(nums[i], nums[nums[i] - 1]); // 将 nums[i] 放置到正确的位置
            } else {
                i++;
            }
        }

        // 再次遍历数组,找到第一个不在正确位置上的正整数,返回它
        for (int i = 0; i < n; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }

        // 如果数组中包含所有正整数,则返回 n+1
        return n + 1;
    }
};

Conocimientos básicos detallados necesarios para cada versión de la solución.

Ir solución :

  1. Sintaxis básica : familiarícese con la sintaxis básica del lenguaje de programación Go, incluida la declaración de variables, bucles, declaraciones condicionales, etc.

  2. Sectores : aprenda sobre el concepto y el uso de sectores en Go, ya que esta solución utiliza sectores para manipular elementos de matriz.

  3. Declaración de función : comprenda cómo se declaran y llaman las funciones de Go, incluidos los parámetros de función y los valores de retorno.

  4. Operaciones de matriz y corte : aprenda a acceder y modificar los elementos de matrices y cortes.

  5. Bucles y declaraciones condicionales : comprenda el uso de bucles for y declaraciones condicionales if, ya que esta solución utiliza estas estructuras de control.

  6. Recursión : en esta solución se utiliza una función recursiva para manejar el intercambio de elementos de la matriz, por lo que también es importante comprender el concepto y la implementación de la recursividad.

Solución de Python :

  1. Sintaxis básica : familiarícese con la sintaxis básica del lenguaje de programación Python, incluidas declaraciones de variables, listas, bucles, declaraciones condicionales, etc.

  2. Listas : aprenda el concepto y el uso de listas en Python, ya que esta solución utiliza listas para almacenar elementos de matriz.

  3. Definición de función : comprenda cómo definir y llamar funciones de Python, incluidos los parámetros de función y los valores de retorno.

  4. Conjuntos : aprenda el concepto y el uso de conjuntos en Python, ya que esta solución utiliza conjuntos para verificar si existe un elemento.

  5. Bucles y declaraciones condicionales : comprenda el uso de bucles for y declaraciones condicionales if, ya que esta solución utiliza estas estructuras de control.

solución Java :

  1. Sintaxis básica : familiarícese con la sintaxis básica del lenguaje de programación Java, incluida la declaración de variables, la matriz, el bucle, la declaración condicional, etc.

  2. Matrices : comprenda el concepto y el uso de matrices en Java, ya que esta solución utiliza matrices para marcar la presencia de números enteros positivos.

  3. Declaración de función : comprenda cómo definir y llamar a métodos Java, incluidos los parámetros del método y los valores de retorno.

  4. Matrices booleanas : aprenda a utilizar matrices booleanas para marcar la presencia de elementos y aprenda a iterar sobre matrices.

  5. Bucles y declaraciones condicionales : comprenda el uso de bucles for y declaraciones condicionales if, ya que esta solución utiliza estas estructuras de control.

Solución C++ :

  1. Sintaxis básica : familiarizado con la sintaxis básica del lenguaje de programación C++, incluidas declaraciones de variables, matrices, bucles, declaraciones condicionales, etc.

  2. Matrices y vectores : comprenda los conceptos y el uso de matrices y vectores en C++, ya que esta solución utiliza matrices para manejar números enteros positivos.

  3. Declaración de función : comprenda cómo definir y llamar funciones de C++, incluidos los parámetros de función y los valores de retorno.

  4. Recursividad : comprenda el concepto y la implementación de la recursividad, ya que esta solución utiliza funciones recursivas.

  5. Bucles y declaraciones condicionales : comprenda el uso de bucles for y declaraciones condicionales if, ya que esta solución utiliza estas estructuras de control.

42. Atrapando Agua De Lluvia

tema

Dados n enteros no negativos que representan un mapa de elevación donde el ancho de cada barra es 1, calcule cuánta agua puede atrapar después de llover.

El mapa de elevación de arriba está representado por la matriz [0,1,0,2,1,0,1,3,2,1,2,1]. En este caso, quedan atrapadas 6 unidades de agua de lluvia (sección azul). ¡Gracias Marcos por aportar esta imagen!

Ejemplo :

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

La idea general del tema.

A partir del eje x, se proporciona una matriz. Los números en la matriz representan el inicio desde el punto (0,0), el ancho es 1 unidad y la altura es el valor del elemento de la matriz. Si llueve, ¿cuántas unidades de agua cabe en ese recipiente?

Ideas para resolver problemas

  • Los valores de los elementos en cada matriz se pueden imaginar como un cilindro con paredes a la izquierda y a la derecha. Por ejemplo, el segundo elemento 1 a la izquierda en la imagen de abajo, el elemento más grande actual a la izquierda es 2, por lo que el agua con una altura de 2 se instalará encima de 1 (porque se imagina que hay paredes de tubos a izquierda y derecha). La idea de esta pregunta es que el puntero izquierdo comienza desde 0 y se desplaza hacia la derecha, y el puntero derecho comienza desde el punto más a la derecha y se desplaza hacia la izquierda. Se necesitan dos variables adicionales para recordar la altura máxima a la izquierda y la altura máxima a la derecha respectivamente. Durante el proceso de atravesar los elementos de la matriz, si la altura del puntero izquierdo es menor que la altura del puntero derecho, el puntero izquierdo se moverá continuamente; de ​​lo contrario, se moverá el puntero derecho. La condición de terminación del bucle es que finaliza cuando los punteros izquierdo y derecho se tocan. Siempre que la altura del elemento en la matriz sea menor que la altura máxima local guardada, se acumula el valor de res; de lo contrario, se actualiza la altura máxima local. La solución final es el valor de res.
  • En resumen, esta pregunta consiste en encontrar para cada i, el valor máximo leftMax a la izquierda y el valor máximo rightMax a la derecha, y luego min(leftMax, rightMax) es la altura que puede alcanzar el agua. Los punteros izquierdo y derecho son punteros de cursor que se mueven hacia el centro. La idea más estúpida para resolver el problema es hacer un bucle hacia la izquierda para cada subíndice i para encontrar el primer valor máximo, un bucle hacia la derecha para encontrar el primer valor máximo y luego tomar el más pequeño de estos dos valores máximos, que es el agua de lluvia actual. Esto tiene una gran complejidad temporal y desperdicia muchos ciclos. Puedo mantener dinámicamente el valor máximo durante el proceso de izquierda a derecha. El valor máximo de la derecha se mantiene utilizando el puntero del cursor de la derecha. Escanee los subíndices de izquierda a derecha y escanee los subíndices de ambos lados hacia el centro, que es el mismo resultado: cada subíndice se ha atravesado una vez.
  • El ancho de cada i se fija en 1, por lo que cada "pozo" solo necesita encontrar la altura, que es la cantidad de agua de lluvia que el "pozo" actual puede acumular. Finalmente, se suma el agua de lluvia de cada “pozo” para determinar la cantidad de agua de lluvia que se puede recibir.

Aquí están las ideas de resolución de problemas para cada versión:

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

  1. Inicialización : Primero, inicializamos la variable resa 0, lefta 0, rightal heightúltimo índice de la matriz maxLefty maxRighta 0.

  2. Recorrido de doble puntero : utilice un bucle para recorrer heightla matriz lefte rightindique respectivamente el índice de las dos columnas de la operación actual.

  3. Sujeción izquierda y derecha : en el bucle comparamos las alturas de height[left]y height[right], si height[left]es menor o igual que height[right], significa que la columna de la izquierda es más baja. En este caso comprobamos height[left]si es mayor que maxLeft. Si es así, actualice maxLefta la altura de la columna izquierda actual; de lo contrario, maxLeft - height[left]agregue a respara indicar la altura del agua de lluvia que se puede recibir y leftmueva el puntero una posición hacia la derecha.

  4. La columna de la derecha es más baja : si height[right]es menor que height[left], significa que la columna de la derecha es más baja. En este caso comprobamos height[right]si es mayor o igual a maxRight. Si es así, actualice maxRighta la altura actual de la columna derecha; de lo contrario, maxRight - height[right]agregue a respara indicar la altura del agua de lluvia que se puede recibir y rightmueva el puntero una posición hacia la izquierda.

  5. Fin del ciclo : repita los pasos anteriores hasta que leftno sea menor o igual a right, lo que significa que los dos punteros se encuentran y se ha recorrido toda la matriz.

  6. Resultado de retorno : Finalmente devuelve res, indicando la cantidad total de agua de lluvia que se puede recibir.

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, excepto que la sintaxis y la declaración de variables son ligeramente diferentes. Los pasos específicos son los siguientes:

  1. Inicialización : la variable de inicialización reses 0, leftes 0, rightes heightel último índice de la matriz maxLefty maxRightambas son 0.

  2. Recorrido de doble puntero : utilice un bucle para recorrer heightla matriz lefte rightindique respectivamente el índice de las dos columnas de la operación actual.

  3. Sujeción izquierda y derecha : en el bucle comparamos las alturas de height[left]y height[right], si height[left]es menor o igual que height[right], significa que la columna de la izquierda es más baja. En este caso comprobamos height[left]si es mayor que maxLeft. Si es así, actualice maxLefta la altura de la columna izquierda actual; de lo contrario, maxLeft - height[left]agregue a respara indicar la altura del agua de lluvia que se puede recibir y leftmueva el puntero una posición hacia la derecha.

  4. La columna de la derecha es más baja : si height[right]es menor que height[left], significa que la columna de la derecha es más baja. En este caso comprobamos height[right]si es mayor o igual a maxRight. Si es así, actualice maxRighta la altura actual de la columna derecha; de lo contrario, maxRight - height[right]agregue a respara indicar la altura del agua de lluvia que se puede recibir y rightmueva el puntero una posición hacia la izquierda.

  5. Fin del ciclo : repita los pasos anteriores hasta que leftno sea menor o igual a right, lo que significa que los dos punteros se encuentran y se ha recorrido toda la matriz.

  6. Resultado de retorno : Finalmente devuelve res, indicando la cantidad total de agua de lluvia que se puede recibir.

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

Las ideas de resolución de problemas de la versión Java son básicamente las mismas que las de las versiones Go y Python, excepto que la sintaxis y las definiciones de los métodos son ligeramente diferentes. Los pasos específicos son los siguientes:

  1. Inicialización : la variable de inicialización reses 0, leftes 0, rightes heightel último índice de la matriz maxLefty maxRightambas son 0.

  2. Recorrido de doble puntero : utilice un bucle para recorrer heightla matriz lefte rightindique respectivamente el índice de las dos columnas de la operación actual.

  3. Sujeción izquierda y derecha : en el bucle comparamos las alturas de height[left]y height[right], si height[left]es menor o igual que height[right], significa que la columna de la izquierda es más baja. En este caso comprobamos height[left]si es mayor que maxLeft. Si es así, actualice maxLefta la altura de la columna izquierda actual; de lo contrario, maxLeft - height[left]agregue a respara indicar la altura del agua de lluvia que se puede recibir y leftmueva el puntero una posición hacia la derecha.

  4. La columna de la derecha es más baja : si height[right]es menor que height[left], significa que la columna de la derecha es más baja. En este caso comprobamos height[right]si es mayor o igual a maxRight. Si es así, actualice maxRighta la altura actual de la columna derecha; de lo contrario, maxRight - height[right]agregue a respara indicar la altura del agua de lluvia que se puede recibir y rightmueva el puntero una posición hacia la izquierda.

  5. Fin del ciclo : repita los pasos anteriores hasta que leftno sea menor o igual a right, lo que significa que los dos punteros se encuentran y se ha recorrido toda la matriz.

6. Devolver resultado : Finalmente devolver res, indicando la cantidad total de agua de lluvia que se puede recibir.

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

Las ideas de resolución de problemas de la versión C++ son básicamente las mismas que las de las versiones Go, Python y Java, excepto que la sintaxis y las definiciones de los métodos son ligeramente diferentes. Los pasos específicos son los siguientes:

  1. Inicialización : la variable de inicialización reses 0, leftes 0, rightes heightel último índice de la matriz maxLefty maxRightambas son 0.

  2. Recorrido de doble puntero : utilice un bucle para recorrer heightla matriz lefte rightindique respectivamente el índice de las dos columnas de la operación actual.

  3. Sujeción izquierda y derecha : en el bucle comparamos las alturas de height[left]y height[right], si height[left]es menor o igual que height[right], significa que la columna de la izquierda es más baja. En este caso comprobamos height[left]si es mayor que maxLeft. Si es así, actualice maxLefta la altura de la columna izquierda actual; de lo contrario, maxLeft - height[left]agregue a respara indicar la altura del agua de lluvia que se puede recibir y leftmueva el puntero una posición hacia la derecha.

  4. La columna de la derecha es más baja : si height[right]es menor que height[left], significa que la columna de la derecha es más baja. En este caso comprobamos height[right]si es mayor o igual a maxRight. Si es así, actualice maxRighta la altura actual de la columna derecha; de lo contrario, maxRight - height[right]agregue a respara indicar la altura del agua de lluvia que se puede recibir y rightmueva el puntero una posición hacia la izquierda.

  5. Fin del ciclo : repita los pasos anteriores hasta que leftno sea menor o igual a right, lo que significa que los dos punteros se encuentran y se ha recorrido toda la matriz.

  6. Resultado de retorno : Finalmente devuelve res, indicando la cantidad total de agua de lluvia que se puede recibir.

En general, no importa qué lenguaje de programación se utilice, la solución a este problema es utilizar el método de sujeción de doble puntero para mantener dinámicamente la altura máxima a la izquierda y la altura máxima a la derecha para calcular la altura del agua de lluvia que cada La posición puede recibir y agregar esto al resultado. Finalmente, el resultado devuelto representa la cantidad total de agua de lluvia que se puede recibir. Los diferentes lenguajes de programación tienen sintaxis y detalles ligeramente diferentes, pero la idea básica sigue siendo la misma.

código

Ir

func trap(height []int) int {
    res, left, right, maxLeft, maxRight := 0, 0, len(height)-1, 0, 0
    // 初始化结果res为0,left为0,right为height数组的最后一个索引,maxLeft和maxRight都为0

    for left <= right {
        // 使用一个循环来遍历height数组,left和right指示当前操作的两个柱子的索引
        if height[left] <= height[right] {
            // 如果左边的柱子高度小于等于右边的柱子
            if height[left] > maxLeft {
                // 如果当前左边柱子的高度大于maxLeft
                maxLeft = height[left]
                // 更新maxLeft为当前左边柱子的高度
            } else {
                res += maxLeft - height[left]
                // 否则,将maxLeft与当前左边柱子的高度之差累加到结果res中
            }
            left++
            // 左边柱子向右移动一位
        } else {
            // 如果右边的柱子高度小于左边的柱子
            if height[right] >= maxRight {
                // 如果当前右边柱子的高度大于等于maxRight
                maxRight = height[right]
                // 更新maxRight为当前右边柱子的高度
            } else {
                res += maxRight - height[right]
                // 否则,将maxRight与当前右边柱子的高度之差累加到结果res中
            }
            right--
            // 右边柱子向左移动一位
        }
    }
    return res
    // 循环结束后,返回结果res,表示可以接到的雨水总量
}

Pitón

class Solution:
    def trap(self, height: List[int]) -> int:
        res, left, right, maxLeft, maxRight = 0, 0, len(height) - 1, 0, 0
        
        while left <= right:
            if height[left] <= height[right]:
                if height[left] > maxLeft:
                    maxLeft = height[left]
                else:
                    res += maxLeft - height[left]
                left += 1
            else:
                if height[right] >= maxRight:
                    maxRight = height[right]
                else:
                    res += maxRight - height[right]
                right -= 1
        
        return res

Java

class Solution {
    public int trap(int[] height) {
        int res = 0, left = 0, right = height.length - 1, maxLeft = 0, maxRight = 0;
        
        while (left <= right) {
            if (height[left] <= height[right]) {
                if (height[left] > maxLeft) {
                    maxLeft = height[left];
                } else {
                    res += maxLeft - height[left];
                }
                left++;
            } else {
                if (height[right] >= maxRight) {
                    maxRight = height[right];
                } else {
                    res += maxRight - height[right];
                }
                right--;
            }
        }
        
        return res;
    }
}

cpp

class Solution {
public:
    int trap(vector<int>& height) {
        int res = 0, left = 0, right = height.size() - 1, maxLeft = 0, maxRight = 0;
        
        while (left <= right) {
            if (height[left] <= height[right]) {
                if (height[left] > maxLeft) {
                    maxLeft = height[left];
                } else {
                    res += maxLeft - height[left];
                }
                left++;
            } else {
                if (height[right] >= maxRight) {
                    maxRight = height[right];
                } else {
                    res += maxRight - height[right];
                }
                right--;
            }
        }
        
        return res;
    }
};

Conocimientos básicos y puntos de sintaxis relacionados con cada versión. Introduciremos las respectivas versiones de código según los cuatro lenguajes de programación Go, Python, Java y C++.

Ir versión:

  1. Definición de función y valor de retorno : en Go, la definición de función utiliza palabras clave funcy el tipo de valor de retorno de la función se coloca después de la lista de parámetros. Por ejemplo, func trap(height []int) intse define una función llamada trapque acepta una porción de números enteros heightcomo parámetro y devuelve un número entero como resultado.

  2. Sectores y matrices : un sector en Go es similar a una matriz dinámica, pero es un tipo de referencia. En el código, heighthay una porción de números enteros que representan la matriz de altura.

  3. Bucles y declaraciones condicionales : Go utiliza forbucles y ifdeclaraciones condicionales para controlar el flujo. En traplas funciones, forlos bucles se utilizan para atravesar matrices ify las declaraciones se utilizan para determinar condiciones.

  4. Declaración y asignación de variables : las variables en Go se pueden declarar mediante varpalabras clave o :=asignarse mediante declaraciones de variables breves. En el código, hay múltiples operaciones de declaración y asignación de variables, como res, left, right, maxLefty maxRight.

  5. Acceso indexado a matrices/porciones : []acceda a los elementos de una matriz o porción mediante corchetes. Por ejemplo, height[left]significa acceder al elemento en el índice heightdel segmento .left

Versión de Python:

  1. Clases y métodos : Python es un lenguaje de programación orientado a objetos, similar a Go, en el sentido de que las funciones se defdefinen mediante la palabra clave. En Python, el primer argumento de un método de clase suele ser selfuna referencia a la propia instancia.

  2. Listas y bucles : una lista en Python es una matriz dinámica, similar a un segmento en Go. Los bucles se forimplementan a través de bucles.

  3. Declaraciones condicionales : al igual que Go, Python usa ifdeclaraciones para realizar juicios condicionales.

  4. Asignación de variables : Python utiliza =operadores para realizar la asignación de variables, como res, left, right, maxLefty maxRight.

Versión de Java:

  1. Clases y métodos : Java es un lenguaje de programación orientado a objetos y las funciones se public int trap(int[] height)definen de esta manera. Es necesario especificar tanto los parámetros del método como los valores de retorno.

  2. Matrices : las matrices en Java tienen un tamaño fijo, en lugar de crecer dinámicamente como los cortes en Go y Python.

  3. Bucles y declaraciones condicionales : Java utiliza forbucles y ifdeclaraciones condicionales para controlar el flujo.

  4. Declaración y asignación de variables : las variables en Java requieren una declaración explícita de tipo y asignación mediante =operadores. En el código, hay múltiples operaciones de declaración y asignación de variables, como res, left, right, maxLefty maxRight.

Versión C++:

  1. Clases y métodos : C++ es un lenguaje de programación multiparadigma y las funciones se int trap(vector<int>& height)definen de esta manera. Es necesario especificar tanto los parámetros del método como los valores de retorno.

  2. Contenedores y bucles : C++ usa vectorcontenedores para representar matrices dinámicas, similares a los sectores y listas en Go y Python. Los bucles se pueden implementar usando foro while.

  3. Declaraciones condicionales : al igual que Go, Python y Java, C++ utiliza ifdeclaraciones para realizar juicios condicionales.

  4. Declaración y asignación de variables : la declaración de variables en C++ suele estar al comienzo de una función o bloque de código y luego se puede =asignar mediante el operador. En el código, hay múltiples operaciones de declaración y asignación de variables, como res, left, right, maxLefty maxRight.

Supongo que te gusta

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