[Backtracking] [leetcode] Devuelve todas las combinaciones posibles de k números en 1 ... n

tema:

Dados dos enteros  n  y  k , devuelve todas las  combinaciones posibles de  k números en 1 ...  .

Ejemplo:

Entrada:  n = 4, k = 2
 Salida:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

fuente:

77. Combinación

Ideas para resolver problemas: retroceder

Quiere usar la búsqueda de fuerza bruta para resolver, pero aún no puede comenzar, entonces usamos el método retrospectivo para resolver.

El retroceso se utiliza junto con la recursividad, el acceso antes de la recursividad y el retroceso después de la recursión. El acceso y el retroceso son un par de operaciones opuestas.

Codigo uno:

class Solution {
public:
    vector< vector<int> > result;
    vector<int> path;

    vector< vector<int> > combine(int n, int k) {
        go(n, k, 1);
        return result;
    }

    void go(int n, int k, int start) {
        if (path.size() == k) {
            // 保存结果
            result.push_back(path);
            return;
        }
        for (int i = start; i <= n; i++) {
            path.push_back(i); // 访问
            go(n, k, i+1); // 递归
            path.pop_back(); // 回溯
        }
    }
};

Codifique una búsqueda de fuerza bruta para todas las combinaciones posibles, incluido path.size () <k. En este caso, se necesita podar para mejorar la eficiencia del código.

Por ejemplo, si el conjunto [1,2,3,4], k = 3, cuando el inicio apunta a 3, solo queda un número 4, que ya es insuficiente. En este momento, no hay necesidad de recursivamente llamar a esta situación.

El número restante: n-start

El número que ya está en la ruta: path.size ()

Inicio actual: 1, (el número al que apunta el inicio no ha entrado en la ruta, ni se ha contado en el resto)

Entonces, cuando el número restante + el número que ya está en la ruta + el inicio actual <k, salga del ciclo. Esta es la condición de poda: n-i + ruta.tamaño () + 1 <k,

Código optimizado dos:

class Solution {
public:
    vector< vector<int> > result;
    vector<int> path;

    vector< vector<int> > combine(int n, int k) {
        go(n, k, 1);
        return result;
    }

    void go(int n, int k, int start) {
        if (path.size() == k) {
            result.push_back(path);
            return;
        }
        for (int i = start; i <= n; i++) {
            if (n - i + path.size() + 1 < k) break;
            path.push_back(i);
            go(n, k, i+1);
            path.pop_back();
        }
    }
};

Retroceso + recursividad, el código escrito es simple y fácil de entender. Escribí el código una vez usando violencia, pero ahora no puedo leerlo por mí mismo. Lo publiqué y lo comparé. Vea el código a continuación.

Significa especificar el primer resultado primero, y cada resultado subsiguiente agrega +1 al resultado anterior, al igual que existe un operador +1: actual = anterior + 1. Tenga en cuenta que el número debe redondearse si excede.

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int combine_size(int n, int k) {
    if (k > n / 2) k = n - k;
    int s = 1;
    for (int i = 1; i <= k; i++) {
        s *= n--;
        s /= i;
    }
    return s;
}

int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
    int sz = combine_size(n, k); // 先计算空间大小
    *returnSize = sz;

    // 申请空间
    int **ret = (int**)malloc(sizeof(int*) * sz);
    int *sizes = (int*)malloc(sizeof(int) * sz);
    for (int i = 0; i < sz; i++) {
        int *t = (int*)malloc(sizeof(int) * (k+1));
        t[k] = n + 1;
        ret[i] = t;
        sizes[i] = k;
    }
    *returnColumnSizes = sizes;

    // 初始第一个结果
    for (int i = 0; i < k; i++) {
        ret[0][i] = i + 1;
    }
    int p = 1;
    while (p < sz) {
        // ret[p] = ret[p-1] + 1
        int *pre = ret[p-1];
        int *cur = ret[p];

        // p指向行,而pos指向列,从最后一列算起
        // n=6 k=3, 1,2,3,6 -> 1,2,4,6
        int pos = k - 1;
        while (pos >= 0) {
            if (pre[pos] < pre[pos+1] - 1) {
                break;
            }
            pos--;
        }
        for (int i = 0; i < pos; i++) {
            cur[i] = pre[i];
        }
        cur[pos] = pre[pos] + 1;
        for (int i = pos + 1; i < k; i++) {
            cur[i] = cur[i-1] + 1;
        }
        p++;
    }
    return ret;
}

 

Supongo que te gusta

Origin blog.csdn.net/hbuxiaoshe/article/details/114704584
Recomendado
Clasificación