491, la solución del algoritmo de retroceso divide la matriz en secuencias de Fibonacci

Inserte la descripción de la imagen aquí

Si desea ver más preguntas de algoritmo, puede escanear el código QR anterior y seguir mi cuenta oficial de WeChat " Estructura de datos y algoritmo ". Hasta ahora, he actualizado más de 500 preguntas de algoritmo en la cuenta oficial , algunas de las cuales tienen han sido clasificados en documentos pdf., A partir de ahora, hay más de 800 páginas en total (y seguirá aumentando), puede responder a la palabra clave "pdf" en la cuenta oficial para descargar.


Descripción del problema

Dada una cadena de números S, como S = "123456579" , podemos dividirla en secuencias similares a Fibonacci [123, 456, 579].


Formalmente, la secuencia de Fibonacci es una lista F de enteros no negativos y satisface:

  • 0 <= F [i] <= 2 ^ 31-1, (es decir, cada entero se ajusta al tipo de entero con signo de 32 bits);
  • F.longitud> = 3 ;
  • Para todo 0 <= i <F.length-2, se cumple F [i] + F [i + 1] = F [i + 2].

Además, tenga en cuenta que al dividir la cadena en bloques pequeños, el número de cada bloque no debe comenzar con un cero, a menos que el bloque sea el mismo número 0.


Devuelve cualquier conjunto de bloques de secuencia similares a Fibonacci divididos de S, o [] si no se puede dividir.


Ejemplo 1:

Entrada : "123456579"

Resultado : [123,456,579]

Ejemplo 2:

Entrada : "11235813"

Resultado : [1,1,2,3,5,8,13]

Ejemplo 3:

Entrada : "112358130"

Salida : []

Explicación : esta tarea no se puede completar.

Ejemplo 4:

Entrada : "0123"

Salida : []

Explicación : El número de cada bloque no puede comenzar con cero, por lo que "01", "2" y "3" no son respuestas válidas.

Ejemplo 5:

Entrada : "1101111"

Salida : [110, 1, 111]

Explicación : La salida [11,0,11,11] también se acepta.


inmediato:

  • 1 <= S. longitud <= 200
  • La cadena S contiene solo números.

Solución de algoritmo de retroceso

Esta pregunta es dividir la cadena S en algunas subcadenas, y estas subcadenas satisfacen la relación de la secuencia de Fibonacci. Para este problema, podemos usar el algoritmo de retroceso para resolverlo. El algoritmo de retroceso es en realidad un proceso de intentos continuos . Una vez que el intento es exitoso, será exitoso. Si el intento falla, volverá al paso anterior. Nota que cuando regrese al paso anterior, Restaurará el estado al estado del paso anterior. El algoritmo de retroceso no se introducirá demasiado aquí. Para las ideas de resolución de problemas del algoritmo de retroceso, puede ver 450. ¿Qué es un algoritmo de retroceso? Puede leerlo a primera vista y será inútil cuando lo escriba .


El algoritmo de retroceso en realidad tiene una plantilla clásica

private void backtrack("原始参数") {
    
    
    //终止条件(递归必须要有终止条件)
    if ("终止条件") {
    
    
        //一些逻辑操作(可有可无,视情况而定)
        return;
    }

    for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) {
    
    
        //一些逻辑操作(可有可无,视情况而定)

        //做出选择

        //递归
        backtrack("新的参数");
        //一些逻辑操作(可有可无,视情况而定)

        //撤销选择
    }
}

Lo mismo es cierto para esta pregunta. Primero interceptemos continuamente la cadena para ver si puede formar una secuencia de Fibonacci. Si no puede, regrese al paso anterior. Si puede, continúe bajando. Para obtener más detalles, veamos mire la figura de abajo., Aquí hay una imagen dibujada con referencia al ejemplo 1, pero el número está abreviado, solo 124557, porque si hay más números, la imagen es demasiado grande para dibujar.

Inserte la descripción de la imagen aquí

Comprenda los principios anteriores, el código es mucho más simple, echemos un vistazo al código

public List<Integer> splitIntoFibonacci(String S) {
    
    
    List<Integer> res = new ArrayList<>();
    backtrack(S.toCharArray(), res, 0);
    return res;
}

public boolean backtrack(char[] digit, List<Integer> res, int index) {
    
    
    //边界条件判断,如果截取完了,并且res长度大于等于3,表示找到了一个组合。
    if (index == digit.length && res.size() >= 3) {
    
    
        return true;
    }
    for (int i = index; i < digit.length; i++) {
    
    
        //两位以上的数字不能以0开头
        if (digit[index] == '0' && i > index) {
    
    
            break;
        }
        //截取字符串转化为数字
        long num = subDigit(digit, index, i + 1);
        //如果截取的数字大于int的最大值,则终止截取
        if (num > Integer.MAX_VALUE) {
    
    
            break;
        }
        int size = res.size();
        //如果截取的数字大于res中前两个数字的和,说明这次截取的太大,直接终止,因为后面越截取越大
        if (size >= 2 && num > res.get(size - 1) + res.get(size - 2)) {
    
    
            break;
        }
        if (size <= 1 || num == res.get(size - 1) + res.get(size - 2)) {
    
    
            //把数字num添加到集合res中
            res.add((int) num);
            //如果找到了就直接返回
            if (backtrack(digit, res, i + 1))
                return true;
            //如果没找到,就会走回溯这一步,然后把上一步添加到集合res中的数字给移除掉
            res.remove(res.size() - 1);
        }
    }
    return false;
}

//相当于截取字符串S中的子串然后转换为十进制数字
private long subDigit(char[] digit, int start, int end) {
    
    
    long res = 0;
    for (int i = start; i < end; i++) {
    
    
        res = res * 10 + digit[i] - '0';
    }
    return res;
}

para resumir

No hay muchos tipos de preguntas algorítmicas que realmente tengan plantillas, pero el algoritmo de retroceso es uno de ellos. Es solo que los diferentes tipos de preguntas deben modificarse de manera diferente. Siempre que domine esta plantilla, puede modificar ligeramente muchos algoritmos de retroceso tipos de preguntas. Es fácil de hacer.

Supongo que te gusta

Origin blog.csdn.net/abcdef314159/article/details/112498301
Recomendado
Clasificación